Source code of Windows XP (NT5)
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.

1798 lines
57 KiB

  1. /************************************************************/
  2. /* Windows Write, Copyright 1985-1992 Microsoft Corporation */
  3. /************************************************************/
  4. /* insert.c -- MW insertion routines */
  5. #define NOCLIPBOARD
  6. #define NOGDICAPMASKS
  7. #define NOCTLMGR
  8. #define NOWINSTYLES
  9. #define NOSYSMETRICS
  10. #define NOMENUS
  11. #define NOKEYSTATE
  12. #define NOHDC
  13. #define NORASTEROPS
  14. #define NOSYSCOMMANDS
  15. #define NOSHOWWINDOW
  16. #define NOCOLOR
  17. //#define NOATOM
  18. #define NOICON
  19. #define NOBRUSH
  20. #define NOCREATESTRUCT
  21. #define NOMB
  22. #define NOFONT
  23. #define NOOPENFILE
  24. #define NOPEN
  25. #define NOREGION
  26. #define NOSCROLL
  27. #define NOSOUND
  28. #define NOWH
  29. #define NOWINOFFSETS
  30. #define NOWNDCLASS
  31. #define NOCOMM
  32. #include <windows.h>
  33. #include "mw.h"
  34. #include "docdefs.h"
  35. #include "editdefs.h"
  36. #include "cmddefs.h"
  37. #include "dispdefs.h"
  38. #include "wwdefs.h"
  39. #include "filedefs.h"
  40. #define NOSTRERRORS
  41. #include "str.h"
  42. #include "propdefs.h"
  43. #include "fmtdefs.h"
  44. #include "fkpdefs.h"
  45. #include "ch.h"
  46. #include "winddefs.h"
  47. #include "fontdefs.h"
  48. #include "debug.h"
  49. #if defined(OLE)
  50. #include "obj.h"
  51. #endif
  52. #ifdef DBCS
  53. #include "dbcs.h"
  54. #endif
  55. #ifdef JAPAN //T-HIROYN Win3.1
  56. #include "kanji.h"
  57. int changeKanjiftc = FALSE;
  58. int newKanjiftc = ftcNil;
  59. #endif
  60. /* E X T E R N A L S */
  61. extern HWND vhWnd; /* WINDOWS: Handle of the current document display window*/
  62. extern MSG vmsgLast; /* WINDOWS: last message gotten */
  63. extern HWND hParentWw; /* WINDOWS: Handle for parent (MENU) window */
  64. extern int vfSysFull;
  65. extern int vfOutOfMemory;
  66. extern int vxpIns;
  67. extern int vdlIns;
  68. extern struct PAP vpapAbs;
  69. extern struct UAB vuab;
  70. extern struct CHP vchpNormal;
  71. extern int vfSeeSel;
  72. extern int vfInsLast;
  73. extern struct FCB (**hpfnfcb)[];
  74. extern typeCP vcpLimParaCache;
  75. extern typeCP vcpFirstParaCache;
  76. extern typeCP CpMax();
  77. extern typeCP CpMin();
  78. extern CHAR rgchInsert[cchInsBlock]; /* Temporary insert buffer */
  79. extern typeCP cpInsert; /* Beginning cp of insert block */
  80. extern int ichInsert; /* Number of chars used in rgchInsert */
  81. extern struct CHP vchpInsert;
  82. extern int vfSelHidden;
  83. extern struct FKPD vfkpdParaIns;
  84. extern struct FKPD vfkpdCharIns;
  85. extern struct PAP vpapPrevIns;
  86. extern typeFC fcMacPapIns;
  87. extern typeFC fcMacChpIns;
  88. extern struct CHP vchpSel;
  89. extern struct FLI vfli;
  90. extern struct PAP *vppapNormal;
  91. extern typeCP cpMinCur;
  92. extern typeCP cpMacCur;
  93. extern struct SEL selCur;
  94. extern int docCur;
  95. extern struct WWD rgwwd[];
  96. extern struct DOD (**hpdocdod)[];
  97. extern int wwCur;
  98. extern struct CHP vchpFetch;
  99. extern struct SEP vsepAbs;
  100. extern int vfCommandKey;
  101. extern int vfShiftKey;
  102. extern int vfOptionKey;
  103. extern int vfInsEnd;
  104. extern typeCP cpWall;
  105. extern int vfDidSearch;
  106. extern int vdocParaCache;
  107. extern typeCP vcpFetch;
  108. extern int vccpFetch;
  109. extern CHAR *vpchFetch;
  110. extern struct CHP vchpFetch;
  111. extern int ferror;
  112. extern BOOL vfInvalid;
  113. extern int docUndo;
  114. extern struct EDL *vpedlAdjustCp;
  115. extern int wwMac;
  116. extern int vfFocus;
  117. extern int vkMinus;
  118. #ifdef CASHMERE
  119. extern int vfVisiMode; /* Whether "show fmt marks" mode is on */
  120. extern int vwwCursLine; /* Window containing cursor */
  121. #endif
  122. extern int vfLastCursor; /* Whether up/down arrow xp goal position is valid */
  123. /* state of the cursor line */
  124. extern int vxpCursLine;
  125. extern int vypCursLine;
  126. extern int vdypCursLine;
  127. extern int vfInsertOn;
  128. /* G L O B A L S */
  129. /* The following used to be defined here */
  130. extern int vcchBlted; /* # chars blted to screen, before line update */
  131. extern int vidxpInsertCache; /* current index of insertion into char width cache */
  132. extern int vdlIns;
  133. extern int vxpIns;
  134. extern int vfTextBltValid;
  135. extern int vfSuperIns;
  136. extern int vdypLineSize;
  137. extern int vdypCursLineIns;
  138. extern int vdypBase;
  139. extern int vypBaseIns;
  140. extern int vxpMacIns;
  141. extern int vdypAfter;
  142. extern struct FMI vfmiScreen;
  143. #ifdef DEBUG
  144. #define STATIC
  145. #else
  146. #define STATIC static
  147. #endif
  148. /* Used in this module only */
  149. typeCP cpStart; /* Start cp of the replacement operation that an Insert is */
  150. typeCP cpLimInserted; /* Last cp inserted */
  151. typeCP cpLimDeleted; /* Last cp deleted */
  152. /* Enumerated type telling what to update */
  153. /* Ordering is such that larger numbers mean that there is more to update */
  154. #define mdInsUpdNothing 0
  155. #define mdInsUpdNextChar 1
  156. #define mdInsUpdOneLine 2
  157. #define mdInsUpdLines 3
  158. #define mdInsUpdWhole 4
  159. void NEAR FormatInsLine();
  160. void NEAR DelChars( typeCP, int );
  161. void NEAR EndInsert();
  162. int NEAR XpValidateInsertCache( int * );
  163. int NEAR FBeginInsert();
  164. #ifdef DBCS
  165. CHAR near GetDBCSsecond();
  166. BOOL FOptAdmitCh(CHAR, CHAR);
  167. int NEAR MdInsUpdInsertW( WORD, WORD, RECT *);
  168. #else
  169. int NEAR MdInsUpdInsertCh( CHAR, CHAR, RECT *);
  170. #endif /* ifdef DBCS */
  171. #ifdef KOREA
  172. int IsInterim = 0;
  173. int WasInterim = 0;
  174. BOOL fInterim = FALSE; // MSCH bklee 12/22/94
  175. #endif
  176. #ifdef DEBUG
  177. int vTune = 0;
  178. #endif
  179. /* AlphaMode -- Handler for insertion, backspace, and forward delete
  180. Alpha mode works by inserting a block of cchInsBlock cp's at the
  181. insertion point. The inserted piece has fn == fnInsert, cpMin == 0.
  182. We AdjustCp for this block as though it contained cchInsBlock cp's,
  183. even though it is initially "empty".
  184. When a character is typed, it is inserted at rgchInsert[ ichInsert++ ].
  185. When rgchInsert is full, it is written to the scratch file, and
  186. Replace'd with a new insertion block.
  187. AlphaMode exits when it encounters a key or event that it cannot handle
  188. (e.g. cursor keys, mouse hits). It then cleans up, writing the insertion
  189. block to the scratch file, and returns
  190. "Fast Insert" is achieved by writing characters directly to the screen
  191. and scrolling the rest of the line out of the way. The line is not updated
  192. until it is necessary (or until we fall through the delay in KcInputNextKey).
  193. During "Fast Insert" (or fast backspace or fast delete), it is important
  194. that ValidateTextBlt will usually NOT be called unless the line containing
  195. the insertion point has been made valid. Otherwise, ValidateTextBlt will
  196. fail to find a valid vdlIns, and call CpBeginLine, which forces an
  197. update of the entire screen.
  198. */
  199. #ifdef KOREA /* global to MdUpIns 90.12.28 */
  200. int dxpCh;
  201. #endif
  202. /* A L P H A M O D E */
  203. AlphaMode( kc )
  204. int kc; /* Keyboard Character */
  205. {
  206. int rgdxp[ ichMaxLine ];
  207. int chShow, dlT, fGraphics;
  208. int mdInsUpd;
  209. int fDocDirty = (**hpdocdod) [docCur].fDirty;
  210. register struct EDL *pedl;
  211. int xpInsLineMac;
  212. int fGotKey = fFalse;
  213. int kcNext;
  214. int fScrollPending = fFalse;
  215. int dxpPending;
  216. int fDelPending = fFalse;
  217. typeCP cpPending;
  218. int cchPending;
  219. int mdInsUpdPending = mdInsUpdNothing;
  220. #ifdef DBCS
  221. BOOL fResetMdInsUpd = TRUE; /* To avoid the blinking cursor at beg. doc or eod. */
  222. CHAR chDBCS2 = '\0'; /* Used to hold the second byte of a DBCS character */
  223. #endif /* DBCS */
  224. #ifdef JAPAN //T-HIROYN Win3.1
  225. RetryAlpha:
  226. if(changeKanjiftc) {
  227. changeKanjiftc = FALSE;
  228. ApplyCLooks(&vchpSel, sprmCFtc, newKanjiftc);
  229. }
  230. changeKanjiftc = FALSE;
  231. #endif
  232. #ifdef DBCS /* was in JAPAN */
  233. if( kc == 0x000d )
  234. kc = 0x000a;
  235. #endif
  236. if (!FWriteOk( fwcReplace ))
  237. { /* Not OK to write on docCur (read-only OR out of memory) */
  238. _beep();
  239. return;
  240. }
  241. /* Shut down the caret blink timer -- we don't want its messages or its cost */
  242. #ifndef DBCS /* was in JAPAN */
  243. KillTimer( vhWnd, tidCaret );
  244. #endif
  245. #ifdef OLDBACKSPACE
  246. /* Backspace in Win 3.0 has been changed to function
  247. identically like the Delete key ..pault 6/20/89 */
  248. /* Handle BACKSPACE when there's a selection. DELETE with selection has already
  249. been filtered out by KcAlphaKeyMessage */
  250. if (kc == kcDelPrev)
  251. /* Make a selection at selection-start preparatory to deleting previous
  252. char, which is accomplished in the loop. */
  253. Select( selCur.cpFirst, selCur.cpFirst );
  254. #endif
  255. /* Set up initial limits for UNDO */
  256. cpStart = selCur.cpFirst; /* Starting cp for insertion */
  257. cpLimDeleted = selCur.cpLim; /* Last cp Deleted */
  258. /* Delete the selection, and make an insert point selection in its stead */
  259. /* Insert point selection inherits the properties of the deleted text */
  260. if (selCur.cpFirst < selCur.cpLim)
  261. {
  262. struct CHP chp;
  263. typeCP cpT;
  264. fDocDirty = TRUE;
  265. cpT = selCur.cpFirst;
  266. /* Get properties of the deleted text */
  267. FetchCp(docCur, cpT, 0, fcmProps);
  268. blt( &vchpFetch, &chp, cwCHP );
  269. if (fnClearEdit(OBJ_INSERTING))
  270. goto Abort;
  271. UpdateWw( wwCur, FALSE );
  272. if (ferror)
  273. goto Abort;
  274. Select(cpT, cpT);
  275. blt( &chp, &vchpSel, cwCHP );
  276. }
  277. else
  278. { /* Current selection is 0 chars wide, no need to delete */
  279. /* Set up UNDO */
  280. noUndo:
  281. NoUndo(); /* Don't combine adjacent operations or
  282. vuab.cp = cp in DelChars will be wrong */
  283. SetUndo( uacDelNS, docCur, cpStart, cp0, docNil, cpNil, cp0, 0);
  284. }
  285. fGraphics = FBeginInsert();
  286. Scribble( 7, (vfSuperIns ? 'S' : 'I') );
  287. vfSelHidden = false;
  288. vfTextBltValid = FALSE;
  289. if (ferror)
  290. /* Ran out of memory trying to insert */
  291. goto Abort;
  292. if (fGraphics)
  293. {
  294. selCur.cpFirst = selCur.cpLim = cpInsert + cchInsBlock;
  295. /* this is to display the paragraph that has been automatically inserted
  296. by edit in FBeginInsert */
  297. UpdateWw(wwCur, fFalse);
  298. if (kc == kcReturn)
  299. kc = kcNil;
  300. }
  301. for ( ; ; (fGotKey ? (fGotKey = fFalse, kc = kcNext) : (kc = KcInputNextKey())) )
  302. { /* Loop til we get a command key we can't handle */
  303. /* KcInputNextKey will return kcNil if a nonkey */
  304. /* event occurs */
  305. RECT rc;
  306. #ifndef KOREA /* has been defined globally */
  307. int dxpCh;
  308. #endif
  309. typeCP cpFirstEdit=cpInsert + ichInsert;
  310. chShow = kc;
  311. mdInsUpd = mdInsUpdNothing;
  312. /* Force exit from loop if out of heap or disk space */
  313. if (vfSysFull || vfOutOfMemory)
  314. kc = kcNil;
  315. #ifdef DBCS
  316. if (kc != kcDelPrev && kc != kcDelNext) {
  317. fResetMdInsUpd = TRUE;
  318. }
  319. #endif /* DBCS */
  320. if (!vfTextBltValid)
  321. ValidateTextBlt();
  322. Assert( vdlIns >= 0 );
  323. pedl = &(**wwdCurrentDoc.hdndl) [vdlIns];
  324. FreezeHp();
  325. SetRect( (LPRECT)&rc, vxpIns+1, pedl->yp - pedl->dyp,
  326. wwdCurrentDoc.xpMac,
  327. min(pedl->yp, wwdCurrentDoc.ypMac));
  328. vfli.doc = docNil;
  329. /* this is a speeder-upper of the switch below */
  330. if (kc <= 0)
  331. switch (kc)
  332. {
  333. /*********************************************************************
  334. ********** START OF BACKSPACE/FORWARD DELETE CODE *******************
  335. *********************************************************************/
  336. CHAR chDelete; /* Variables for Backspace/Delete */
  337. typeCP cpDelete;
  338. int cchDelete;
  339. int idxpDelete;
  340. int fCatchUp;
  341. #ifdef DBCS
  342. typeCP cpT;
  343. case kcDelNext: /* Delete following character */
  344. cpT = selCur.cpFirst;
  345. if (fDelPending) {
  346. cpT += cchPending;
  347. }
  348. if (cpT >= cpMacCur) {
  349. _beep();
  350. MeltHp();
  351. if (fResetMdInsUpd) {
  352. mdInsUpd = mdInsUpdOneLine;
  353. fResetMdInsUpd = FALSE;
  354. }
  355. goto DoReplace; /* Clean up pending replace ops */
  356. }
  357. cpDelete = CpFirstSty(cpT, styChar);
  358. cchDelete = CpLimSty(cpDelete, styChar) - cpDelete;
  359. goto DeleteChars;
  360. case kcDelPrev: /* Delete previous char */
  361. /* To reflect the state of cpPending and cchPending so that */
  362. /* CpFirstSty( , styChar) is called with a proper cp. */
  363. cpT = cpFirstEdit - 1;
  364. if (fDelPending) {
  365. cpT -= cchPending;
  366. }
  367. if (cpT < cpMinCur) {
  368. _beep();
  369. MeltHp();
  370. if (fResetMdInsUpd) {
  371. mdInsUpd = mdInsUpdOneLine;
  372. fResetMdInsUpd = FALSE;
  373. }
  374. goto DoReplace;
  375. }
  376. cpDelete = CpFirstSty(cpT, styChar);
  377. cchDelete = CpLimSty(cpDelete, styChar) - cpDelete;
  378. #if defined(NEED_FOR_NT351_TAIWAN) //Removed by bklee //solve BkSp single byte (>0x80) infinite loop problem, MSTC - pisuih, 2/24/93
  379. if ( cchDelete > 1 && (cpDelete + cchDelete + cchInsBlock) > cpMacCur )
  380. cchDelete = 1;
  381. #endif TAIWAN
  382. #else
  383. case kcDelNext: /* Delete following character */
  384. cpDelete = selCur.cpFirst;
  385. if (fDelPending)
  386. cpDelete += cchPending;
  387. if (cpDelete >= cpMacCur)
  388. {
  389. _beep();
  390. MeltHp();
  391. goto DoReplace; /* Clean up pending replace ops */
  392. }
  393. FetchCp( docCur, cpDelete, 0, fcmChars );
  394. chDelete = *vpchFetch;
  395. cchDelete = 1;
  396. #ifdef CRLF
  397. if ((chDelete == chReturn) && (*(vpchFetch+1) == chEol) )
  398. {
  399. cchDelete++;
  400. chDelete = chEol;
  401. }
  402. #endif
  403. goto DeleteChars;
  404. case kcDelPrev: /* Delete previous char */
  405. /* Decide what char, cp we're deleting */
  406. cpDelete = cpFirstEdit - 1;
  407. if (fDelPending)
  408. cpDelete -= cchPending;
  409. if (cpDelete < cpMinCur)
  410. {
  411. _beep();
  412. MeltHp();
  413. goto DoReplace; /* Clean up pending replace ops */
  414. }
  415. FetchCp( docCur, cpDelete, 0, fcmChars );
  416. chDelete = *vpchFetch;
  417. cchDelete = 1;
  418. #ifdef CRLF
  419. if ( (chDelete == chEol) && (cpDelete > cpMinCur) )
  420. {
  421. FetchCp( docCur, cpDelete - 1, 0, fcmChars );
  422. if (*vpchFetch == chReturn)
  423. {
  424. cchDelete++;
  425. cpDelete--;
  426. }
  427. }
  428. #endif
  429. #endif /* DBCS */
  430. DeleteChars:
  431. #ifdef DBCS
  432. /* They expect chDelete as well as cpDelete and cchDelete */
  433. FetchCp(docCur, cpDelete, 0, fcmChars);
  434. chDelete = *vpchFetch;
  435. #endif
  436. /* Here we have cpDelete, cchDelete */
  437. /* Also cchPending and cpPending if fDelPending is TRUE */
  438. /* Also dxpPending if fScrollPending is TRUE */
  439. if ( CachePara( docCur, cpDelete ), vpapAbs.fGraphics)
  440. { /* Trying to del over picture, illegal case */
  441. _beep();
  442. MeltHp();
  443. goto DoReplace; /* Clean up pending replace ops */
  444. }
  445. /* Insert properties are now the properties of the
  446. deleted char(s) */
  447. FetchCp( docCur, cpDelete, 0, fcmProps );
  448. vchpFetch.fSpecial = FALSE;
  449. NewChpIns( &vchpFetch );
  450. /* Pending replace operation <-- union of any pending
  451. replace operations with the current one */
  452. if (fDelPending)
  453. {
  454. if (cpPending >= cchDelete)
  455. {
  456. cchPending += cchDelete;
  457. if (kc == kcDelPrev)
  458. cpPending -= cchDelete;
  459. }
  460. else
  461. Assert( FALSE );
  462. }
  463. else
  464. {
  465. cpPending = cpDelete;
  466. cchPending = cchDelete;
  467. fDelPending = TRUE;
  468. }
  469. /* Determine whether the screen update for the current
  470. deletion can be accomplished by scrolling.
  471. We can scroll if:
  472. (1) we are still on the line vdlIns,
  473. (2) we are not deleting eol or chsect,
  474. (3) our width cache is good OR vdlIns is valid, so we can
  475. validate the cache w/o redisplaying the line
  476. */
  477. mdInsUpd = mdInsUpdOneLine;
  478. if ((idxpDelete = (int) (cpDelete - pedl->cpMin)) < 0)
  479. {
  480. mdInsUpd = mdInsUpdLines;
  481. }
  482. else if ((chDelete != chEol) && (chDelete != chSect) &&
  483. (vidxpInsertCache != -1 || pedl->fValid) &&
  484. (mdInsUpdPending < mdInsUpdOneLine))
  485. { /* OK to scroll -- do all pending scrolls */
  486. int fDlAtEndMark;
  487. int fCatchUp;
  488. MeltHp();
  489. /* Re-entrant heap movement */
  490. fCatchUp = FImportantMsgPresent();
  491. if (vidxpInsertCache == -1)
  492. { /* Width cache is invalid, update it */
  493. xpInsLineMac = XpValidateInsertCache( rgdxp ); /* HM */
  494. }
  495. pedl = &(**wwdCurrentDoc.hdndl) [vdlIns];
  496. FreezeHp();
  497. /* Obtain display width of character to delete */
  498. if ((vcchBlted > 0) && (kc == kcDelPrev))
  499. { /* Deleted char was blted in superins mode
  500. onto a line that has not been updated */
  501. vcchBlted--;
  502. /* Because chDelete is always 1 byte quantity
  503. by itself or the 1st byte of the DBCS character
  504. it is OK. */
  505. dxpCh = DxpFromCh( chDelete, FALSE );
  506. }
  507. else
  508. {
  509. int idxpT = idxpDelete + cchDelete;
  510. #ifdef DBCS
  511. /* For the following segment of code to work,
  512. an element in rgdxp corresponding to the second
  513. byte of a DBCS character must contain 0. */
  514. int *pdxpT;
  515. int cchT;
  516. for (dxpCh = 0, pdxpT = &rgdxp[idxpDelete], cchT = 0;
  517. cchT < cchDelete;
  518. dxpCh += *pdxpT++, cchT++);
  519. #else
  520. dxpCh = rgdxp[ idxpDelete ];
  521. #endif
  522. /* Adjust the character width cache to eliminate
  523. width entries for deleted chars */
  524. if ((vidxpInsertCache >= 0) &&
  525. (idxpDelete >= 0) &&
  526. (idxpT <= pedl->dcpMac) )
  527. {
  528. blt( &rgdxp[ idxpT ], &rgdxp[ idxpDelete ],
  529. ichMaxLine - idxpT );
  530. if (vidxpInsertCache > idxpDelete)
  531. /* Deleted behind insert point, adjust index */
  532. vidxpInsertCache -= cchDelete;
  533. }
  534. else
  535. vidxpInsertCache = -1;
  536. }
  537. /* pending scroll op <-- current scroll op merged
  538. with pending scroll op */
  539. if (fScrollPending)
  540. {
  541. dxpPending += dxpCh;
  542. }
  543. else
  544. {
  545. dxpPending = dxpCh;
  546. fScrollPending = fTrue;
  547. }
  548. /* See if we should postpone the scroll */
  549. if (fCatchUp)
  550. {
  551. MeltHp();
  552. Assert( !fGotKey );
  553. fGotKey = TRUE;
  554. if ((kcNext = KcInputNextKey()) == kc)
  555. { /* Next key is same as this key, process NOW */
  556. continue;
  557. }
  558. FreezeHp();
  559. }
  560. /* Perform all pending scrolls */
  561. fScrollPending = fFalse;
  562. if (dxpPending > 0)
  563. {
  564. ClearInsertLine();
  565. if (kc == kcDelPrev)
  566. { /* Backspace */
  567. vxpCursLine = (vxpIns -= dxpPending);
  568. rc.left -= dxpPending;
  569. }
  570. ScrollCurWw( &rc, -dxpPending, 0 );
  571. DrawInsertLine();
  572. xpInsLineMac -= dxpPending;
  573. }
  574. /* See if we can get away without updating the screen
  575. (and without invalidating the insert cache) */
  576. #define cchGetMore 4
  577. #define dxpGetMore ((unsigned)dxpCh << 3)
  578. /* Check for running out of chars ahead of the cursor */
  579. fDlAtEndMark = (pedl->cpMin + pedl->dcpMac >= cpMacCur);
  580. if ( (kc != kcDelNext && fDlAtEndMark) ||
  581. ((idxpDelete + cchGetMore < pedl->dcpMac) &&
  582. ( (int) (xpInsLineMac - vxpIns) > dxpGetMore) ))
  583. {
  584. mdInsUpd = mdInsUpdNothing;
  585. }
  586. /* Special check to avoid two end marks: see if the
  587. dl after the ins line is dirty and beyond the
  588. doc's end */
  589. if (fDlAtEndMark &&
  590. (vdlIns < wwdCurrentDoc.dlMac - 1) &&
  591. !(pedl+1)->fValid)
  592. {
  593. mdInsUpd = mdInsUpdLines;
  594. }
  595. } /* End of "if OK to scroll" */
  596. /* See if we should postpone the replace */
  597. MeltHp();
  598. /* Re-entrant Heap Movement */
  599. if (FImportantMsgPresent() && !fGotKey)
  600. {
  601. fGotKey = TRUE;
  602. if ((kcNext = KcInputNextKey()) == kc)
  603. { /* Next key is same as this key, process NOW */
  604. if (mdInsUpd > mdInsUpdPending)
  605. {
  606. /* Mark screen update as pending */
  607. mdInsUpdPending = mdInsUpd;
  608. vidxpInsertCache = -1;
  609. }
  610. continue;
  611. }
  612. }
  613. /* Handle actual replacement of chars */
  614. DoReplace: if (fDelPending)
  615. {
  616. DelChars( cpPending, cchPending ); /* HM */
  617. fDelPending = fFalse;
  618. }
  619. /* Set up screen update based on present & pending needs */
  620. if (mdInsUpdPending > mdInsUpd)
  621. mdInsUpd = mdInsUpdPending;
  622. if (mdInsUpd >= mdInsUpdOneLine)
  623. /* If we're updating at least a line, assume we're
  624. handling all necessary pending screen update */
  625. mdInsUpdPending = mdInsUpdNothing;
  626. /* Adjust vdlIns's dcpMac. vdlIns is invalid anyway,
  627. and this allows us to catch the case
  628. in which we run out of visible characters to scroll
  629. in the forward delete case. See update test after
  630. the scroll above */
  631. (**wwdCurrentDoc.hdndl) [vdlIns].dcpMac -= cchPending;
  632. /* this is here to compensate for RemoveDelFtnText */
  633. selCur.cpFirst = selCur.cpLim = cpInsert + (typeCP)cchInsBlock;
  634. cpFirstEdit = cpPending;
  635. goto LInvalIns; /* Skip ahead to update the screen */
  636. /*********************************************************************
  637. ************ END OF BACKSPACE/FORWARD DELETE CODE *******************
  638. *********************************************************************/
  639. case kcReturn: /* Substitute EOL for return key */
  640. /* Also add a return if CRLF is on */
  641. MeltHp();
  642. #ifdef CRLF
  643. #ifdef DBCS
  644. MdInsUpdInsertW( MAKEWORD(0, chReturn),
  645. MAKEWORD(0, chReturn), &rc );
  646. #else
  647. MdInsUpdInsertCh( chReturn, chReturn, &rc );
  648. #endif /* DBCS */
  649. #endif
  650. FreezeHp();
  651. kc = chEol;
  652. break;
  653. #ifdef CASHMERE /* These key codes are omitted from MEMO */
  654. case kcNonReqHyphen: /* Substitute for non-required hyphen */
  655. kc = chNRHFile;
  656. chShow = chHyphen;
  657. break;
  658. case kcNonBrkSpace: /* Substitute for non-breaking space */
  659. kc = chNBSFile;
  660. chShow = chSpace;
  661. break;
  662. case kcNLEnter: /* Substitute for non-para return */
  663. kc = chNewLine;
  664. break;
  665. #endif
  666. #ifdef PRINTMERGE
  667. case kcLFld: /* Substitite for Left PRINT MERGE bracket */
  668. chShow = kc = chLFldFile;
  669. break;
  670. case kcRFld: /* Substitute for Right PRINT MERGE bracket */
  671. chShow = kc = chRFldFile;
  672. break;
  673. #endif
  674. case kcPageBreak:
  675. kc = chSect; /* Page break (no section) */
  676. if (wwdCurrentDoc.fEditHeader || wwdCurrentDoc.fEditFooter)
  677. { /* Page breaks prohibited in header/footer */
  678. BadKey: _beep();
  679. MeltHp();
  680. continue;
  681. }
  682. break;
  683. case kcTab: /* Tab */
  684. kc = chTab;
  685. break;
  686. default:
  687. #if WINVER >= 0x300
  688. if (kc == kcNonReqHyphen) /* Substitute for non-required hyphen */
  689. {
  690. /* no longer a const so can't be directly in switch */
  691. kc = chNRHFile;
  692. chShow = chHyphen;
  693. break;
  694. }
  695. #endif
  696. /* AlphaMode Exit point: Found key or event
  697. that we don't know how to handle */
  698. MeltHp();
  699. goto EndAlphaMode;
  700. } /* end of if kc < 0 switch (kc) */
  701. MeltHp();
  702. #ifdef DBCS
  703. if (IsDBCSLeadByte(kc)) {
  704. /* We are dealing with the first byte of the DBCS character. */
  705. /* In case of DBCS letter, wInsert is equal to wShow. */
  706. #ifdef JAPAN //T-HIROYN Win3.1
  707. if( ftcNil != (newKanjiftc = GetKanjiFtc(&vchpInsert)) ) { //(menu.c)
  708. changeKanjiftc = TRUE;
  709. goto EndAlphaMode;
  710. }
  711. #endif
  712. if ((chDBCS2 = GetDBCSsecond()) != '\0') {
  713. mdInsUpd = MdInsUpdInsertW( MAKEWORD(kc, chDBCS2),
  714. MAKEWORD(kc, chDBCS2), &rc );
  715. }
  716. } else {
  717. #ifdef JAPAN //T-HIROYN Win3.1
  718. if (FKana(kc)) {
  719. if( ftcNil != (newKanjiftc = GetKanjiFtc(&vchpInsert)) ) {
  720. changeKanjiftc = TRUE;
  721. goto EndAlphaMode;
  722. }
  723. }
  724. #endif
  725. mdInsUpd = MdInsUpdInsertW( MAKEWORD(0, kc), MAKEWORD(0, chShow), &rc);
  726. }
  727. #else
  728. /* Insert character kc into the document. Show character chShow (which is
  729. equal to kc except for cases such as non-breaking space, etc. */
  730. mdInsUpd = MdInsUpdInsertCh( kc, chShow, &rc );
  731. #endif /* DBCS */
  732. /* common for insert and backspace: invalidate line and previous line if
  733. dependency warrants it */
  734. /* have vdlIns from ValidateTextBlt */
  735. LInvalIns:
  736. pedl = &(**wwdCurrentDoc.hdndl) [vdlIns];
  737. pedl->fValid = fFalse;
  738. wwdCurrentDoc.fDirty = fTrue;
  739. Assert( vdlIns >= 0 );
  740. if ((dlT = vdlIns) == 0)
  741. { /* Editing in first line of window */
  742. if ( wwdCurrentDoc.fCpBad ||
  743. (wwdCurrentDoc.cpFirst + wwdCurrentDoc.dcpDepend > cpFirstEdit) )
  744. { /* Edit affects ww's first cp; recompute it */
  745. CtrBackDypCtr( 0, 0 );
  746. (**wwdCurrentDoc.hdndl) [vdlIns].cpMin = CpMax( wwdCurrentDoc.cpMin,
  747. wwdCurrentDoc.cpFirst );
  748. mdInsUpd = mdInsUpdLines;
  749. }
  750. }
  751. else
  752. { /* If the edit affects the line prior to vdlIns, invalidate it */
  753. --pedl;
  754. #ifdef DBCS
  755. if (!IsDBCSLeadByte(kc)) {
  756. chDBCS2 = kc;
  757. kc = '\0';
  758. }
  759. #endif /* DBCS */
  760. if ((pedl->cpMin + pedl->dcpMac + pedl->dcpDepend > cpFirstEdit))
  761. {
  762. pedl->fValid = fFalse;
  763. dlT--;
  764. }
  765. #ifdef DBCS /* was in JAPAN; KenjiK '90-11-03 */
  766. // deal with the character beyond end of the line.
  767. else
  768. #ifdef KOREA /* protect from displaying picture abnormally */
  769. if(((pedl+1)->cpMin == cpFirstEdit && FOptAdmitCh(kc, chDBCS2))
  770. && !pedl->fGraphics)
  771. #else
  772. if ((pedl+1)->cpMin == cpFirstEdit && FOptAdmitCh(kc, chDBCS2))
  773. #endif
  774. {
  775. /* We do exactly the same as above, except setting
  776. mdInsUpd, because the one returned by MdInsUpdInsertW()
  777. does not reflect this condition. */
  778. pedl->fValid = fFalse;
  779. dlT--;
  780. mdInsUpd = mdInsUpdOneLine;
  781. }
  782. #endif
  783. else
  784. pedl++;
  785. }
  786. #ifdef ENABLE /* We now support end-of-line cursor while inserting because of
  787. typing before splats */
  788. if (vfInsEnd)
  789. { /* forget about special end-of-line cursor */
  790. vfInsEnd = fFalse;
  791. ClearInsertLine();
  792. }
  793. #endif
  794. #ifdef KOREA /* 90.12.28 sangl */
  795. {
  796. BOOL UpNext=FALSE;
  797. screenup:
  798. #endif
  799. switch (mdInsUpd) {
  800. default:
  801. case mdInsUpdNothing:
  802. case mdInsUpdNextChar:
  803. break;
  804. case mdInsUpdLines:
  805. case mdInsUpdOneLine:
  806. ClearInsertLine();
  807. if ( FUpdateOneDl( dlT ) )
  808. { /* Next line affected */
  809. struct EDL *pedl;
  810. if ( (mdInsUpd == mdInsUpdLines) ||
  811. /* Re-entrant heap movement */
  812. !FImportantMsgPresent() ||
  813. (pedl = &(**wwdCurrentDoc.hdndl) [dlT],
  814. (selCur.cpFirst >= pedl->cpMin + pedl->dcpMac)))
  815. {
  816. FUpdateOneDl( dlT + 1 );
  817. }
  818. }
  819. #ifdef KOREA /* 90.12.28 sangl */
  820. else if (UpNext && ((dlT+1) < wwdCurrentDoc.dlMac))
  821. FUpdateOneDl(dlT + 1);
  822. #endif
  823. ToggleSel(selCur.cpFirst, selCur.cpLim, fTrue);
  824. break;
  825. case mdInsUpdWhole:
  826. ClearInsertLine();
  827. UpdateWw(wwCur, fFalse);
  828. ToggleSel(selCur.cpFirst, selCur.cpLim, fTrue);
  829. break;
  830. } /* end switch (mdInsUpd) */
  831. #ifdef KOREA /* 90.12.28 sangl */
  832. if (IsInterim) {
  833. if (mdInsUpd>=mdInsUpdOneLine) {
  834. ClearInsertLine();
  835. vxpCursLine -= dxpCh;
  836. DrawInsertLine();
  837. }
  838. // while ( ((kc=KcInputNextHan()) < 0xA1) || (kc>0xFE) );
  839. while ( (((kc=KcInputNextHan()) < 0x81) || (kc>0xFE)) && (kc != VK_MENU)); // MSCH bklee 12/22/94
  840. if(kc == VK_MENU) { // MSCH bklee 12/22/94
  841. fInterim = IsInterim = 0;
  842. ichInsert -= 2;
  843. goto nextstep;
  844. }
  845. chDBCS2 = GetDBCSsecond();
  846. mdInsUpd = MdInsUpdInsertW(MAKEWORD(kc, chDBCS2),
  847. MAKEWORD(kc, chDBCS2), &rc);
  848. if (vfSuperIns)
  849. goto LInvalIns; /* This is for large size, when 1st interim
  850. becomes final (ex, consonants) */
  851. else {
  852. UpNext = TRUE; /* For italic, try to FUpdateOneDl for
  853. current line */
  854. goto screenup; /* 90.12.28 sangl */
  855. }
  856. } /* ex: all consonants */
  857. } /* For screenup: 90.12.28 sangl */
  858. nextstep : // MSCH bklee 12/22/94
  859. /* if(IsInterim && kc == VK_MENU) { // MSCH bklee 12/22/94
  860. ClearInsertLine();
  861. UpdateWw(wwCur, fFalse);
  862. goto EndAlphaMode;
  863. } */
  864. if (WasInterim)
  865. { MSG msg;
  866. int wp;
  867. if (PeekMessage ((LPMSG)&msg, vhWnd, WM_KEYDOWN, WM_KEYUP, PM_NOYIELD | PM_NOREMOVE) )
  868. { if( msg.message==WM_KEYDOWN &&
  869. ( (wp=msg.wParam)==VK_LEFT || wp==VK_UP || wp==VK_RIGHT ||
  870. wp==VK_DOWN || wp==VK_DELETE) )
  871. goto EndAlphaMode;
  872. }
  873. WasInterim = 0;
  874. }
  875. #endif /* KOREA */
  876. } /* end for */
  877. EndAlphaMode:
  878. Scribble( 7, 'N' );
  879. EndInsert(); /* Clean Up Insertion Block */
  880. #ifdef CASHMERE
  881. UpdateOtherWws(fFalse);
  882. #endif
  883. if (cpLimInserted != cpStart)
  884. { /* We inserted some characters */
  885. SetUndo( uacInsert, docCur, cpStart,
  886. cpLimInserted - cpStart, docNil, cpNil, cp0, 0 );
  887. SetUndoMenuStr(IDSTRUndoTyping);
  888. }
  889. else if (cpLimDeleted == cpStart)
  890. /* This AlphaMode invocation had no net effect */
  891. {
  892. Abort:
  893. NoUndo();
  894. if (!fDocDirty)
  895. /* The doc was clean when we started, & we didn't change it, so
  896. it's still clean */
  897. (**hpdocdod) [docCur].fDirty = FALSE;
  898. }
  899. vfLastCursor = fFalse; /* Tells MoveUpDown to recalc its xp seek position */
  900. if (vfFocus)
  901. {
  902. /* Restore the caret blink timer */
  903. SetTimer( vhWnd, tidCaret, GetCaretBlinkTime(), (FARPROC)NULL );
  904. }
  905. else
  906. {
  907. ClearInsertLine();
  908. }
  909. /* Backspaces/deletes may have changed vchpSel -- update it */
  910. blt( &vchpInsert, &vchpSel, cwCHP );
  911. #ifdef KOREA
  912. if (WasInterim)
  913. { MoveLeftRight(kcLeft);
  914. WasInterim = 0;
  915. vfSeeSel = TRUE;
  916. }
  917. else
  918. vfSeeSel = TRUE; /* Tell Idle() to scroll the selection into view */
  919. #else
  920. vfSeeSel = TRUE; /* Tell Idle() to scroll the selection into view */
  921. #endif
  922. #ifdef JAPAN //T-HIROYN Win3.1
  923. if(changeKanjiftc) {
  924. goto RetryAlpha;
  925. }
  926. #endif
  927. }
  928. /* F B E G I N I N S E R T */
  929. /* Prepare for start of insertion */
  930. /* returns true iff inserting in front of a pic */
  931. int NEAR FBeginInsert()
  932. {
  933. int fGraphics;
  934. typeCP cp = selCur.cpFirst;
  935. typeCP cpFirstPara;
  936. cpInsert = cp;
  937. /* We expect the caller to have deleted the selection already */
  938. Assert (selCur.cpLim == selCur.cpFirst);
  939. /* Use super-fast text insertion unless we are inserting italics */
  940. CachePara(docCur, cp);
  941. cpFirstPara = vcpFirstParaCache;
  942. fGraphics = vpapAbs.fGraphics;
  943. vfSuperIns = !vchpSel.fItalic;
  944. vchpSel.fSpecial = fFalse;
  945. NewChpIns(&vchpSel);
  946. ichInsert = 0; /* Must Set this BEFORE calling Replace */
  947. /* Insert the speeder-upper QD insert block. Note: we invalidate since there
  948. will be a character inserted anyway, plus to make sure that the line
  949. length gets updated ("Invalidate" refers to the choice of Replace() over
  950. the Repl1/AdjustCp/!vfInvalid mechanism used in EndInsert, in which the
  951. insert dl is not made invalid). It would be possible to optimize
  952. by NOT invalidating here (thus being able to blt the first char typed),
  953. but one would have to account for the case in which the cpMin of the
  954. insert dl is changed by AdjustCp, or FUpdateOneDl will get messed up.
  955. Currently this case is covered by an implicit UpdateWw, which occurs
  956. in AlphaMode->ValidateTextBlt->CpBeginLine because we have invalidated vdlIns. */
  957. Replace(docCur, cpInsert, cp0, fnInsert, fc0, (typeFC) cchInsBlock);
  958. cpLimInserted = cpInsert + cchInsBlock;
  959. vidxpInsertCache = -1; /* Char width cache for insert line is initially empty */
  960. /* Blank the mouse cursor so it doesn't make the display look ugly
  961. or slow us down trying to keep it up to date */
  962. SetCursor( (HANDLE) NULL );
  963. return fGraphics;
  964. }
  965. /* E N D I N S E R T */
  966. void NEAR EndInsert()
  967. { /* Clean up from quick insert mode */
  968. int dcp = cchInsBlock - ichInsert;
  969. typeFC fc;
  970. #ifdef CASHMERE
  971. UpdateOtherWws(fTrue);
  972. #endif
  973. fc = FcWScratch(rgchInsert, ichInsert);
  974. #if WINVER >= 0x300
  975. if (!vfSysFull)
  976. /* The "tape dispenser bug replication method" has shown that
  977. holding down a key for 64k presses will cause FcWScratch()
  978. to run out of scratch-file space and fail. If we go ahead
  979. with the Replacement we'll corrupt the piece table, so we
  980. delicately avoid that problem 3/14/90..pault */
  981. #endif
  982. {
  983. Repl1(docCur, cpInsert, (typeCP) cchInsBlock, fnScratch, fc, (typeFC) ichInsert);
  984. cpLimInserted -= (cchInsBlock - ichInsert);
  985. /* adjust separately, since first ichInsert characters have not changed at all */
  986. vfInvalid = fFalse;
  987. vpedlAdjustCp = (struct EDL *)0;
  988. AdjustCp(docCur, cpInsert + ichInsert, (typeCP) dcp, (typeFC) 0);
  989. /* if the line is not made invalid, the length of the line
  990. must be maintained.
  991. */
  992. if (vpedlAdjustCp)
  993. vpedlAdjustCp->dcpMac -= dcp;
  994. }
  995. vfInvalid = fTrue;
  996. cpWall = selCur.cpLim;
  997. vfDidSearch = fFalse;
  998. if (!vfInsertOn)
  999. DrawInsertLine();
  1000. }
  1001. /* N E W C H P I N S */
  1002. NewChpIns(pchp)
  1003. struct CHP *pchp;
  1004. { /* Make forthcoming inserted characters have the look in pchp */
  1005. if (CchDiffer(&vchpInsert, pchp, cchCHP) != 0)
  1006. { /* Add the run for the previous insertion; our looks differ. */
  1007. typeFC fcMac = (**hpfnfcb)[fnScratch].fcMac;
  1008. if (fcMac != fcMacChpIns)
  1009. {
  1010. AddRunScratch(&vfkpdCharIns, &vchpInsert, &vchpNormal, cchCHP, fcMac);
  1011. fcMacChpIns = fcMac;
  1012. }
  1013. blt(pchp, &vchpInsert, cwCHP);
  1014. }
  1015. }
  1016. #ifdef DBCS
  1017. int NEAR MdInsUpdInsertW(wInsert, wShow, prcScroll)
  1018. WORD wInsert; /* Char or 2 char's to insert into document */
  1019. WORD wShow; /* Char or 2 char's to be shown on screen (SuperIns mode only) */
  1020. RECT *prcScroll; /* Rect to scroll for SuperIns */
  1021. #else
  1022. int NEAR MdInsUpdInsertCh( chInsert, chShow, prcScroll )
  1023. CHAR chInsert; /* Char to insert into document */
  1024. CHAR chShow; /* Char to show on screen (SuperIns mode only) */
  1025. RECT *prcScroll; /* Rect to scroll for SuperIns */
  1026. #endif /* DBCS */
  1027. { /* Insert character ch into the document. Show char chShow. */
  1028. /* Flush the insert buffer to the scratch file if it fills up */
  1029. /* Return: mdInsUpdWhole - Must do an UpdateWw
  1030. mdInsUpdNextChar - Update not mandatory, char waiting
  1031. mdInsUpdLines - Must update vdlIns and maybe following
  1032. mdInsUpdNothing - No update needed & no char waiting
  1033. mdInsUpdOneLine - Update vdlIns; only update following
  1034. if there's no char waiting
  1035. */
  1036. extern int vfInsFontTooTall;
  1037. void NEAR FlushInsert();
  1038. int mdInsUpd;
  1039. #ifndef KOREA /* has been defined globally */
  1040. int dxpCh;
  1041. #endif
  1042. int dl;
  1043. #ifdef DBCS
  1044. CHAR chInsert;
  1045. CHAR chShow;
  1046. BOOL fDBCSChar;
  1047. int ichInsertSave;
  1048. int dcchBlted;
  1049. #endif /* DBCS */
  1050. #ifdef KOREA
  1051. if (IsInterim)
  1052. ichInsert -= 2;
  1053. #endif
  1054. #ifdef DIAG
  1055. {
  1056. char rgch[200];
  1057. wsprintf(rgch, "MdInsUpdInsertCh: ichInsert %d cpInsert %lu\n\r ",ichInsert, cpInsert);
  1058. CommSz(rgch);
  1059. }
  1060. #endif
  1061. Assert(ichInsert <= cchInsBlock);
  1062. if (ichInsert >= cchInsBlock) /* Should never be >, but... */
  1063. FlushInsert();
  1064. #ifdef DBCS
  1065. ichInsertSave = ichInsert;
  1066. if (HIBYTE(wInsert) != '\0') {
  1067. fDBCSChar = TRUE;
  1068. #ifdef KOREA /* 90.12.28 sangl */
  1069. // if (LOBYTE(HIWORD(vmsgLast.lParam)) == 0xF0)
  1070. if (fInterim || LOBYTE(HIWORD(vmsgLast.lParam)) == 0xF0) // MSCH bklee 12/22/94
  1071. {
  1072. if (IsInterim == 0) dxpCh = DxpFromCh( wInsert, FALSE ); // fix bug #5382
  1073. IsInterim ++;
  1074. }
  1075. else
  1076. {
  1077. WasInterim = IsInterim;
  1078. IsInterim = 0;
  1079. }
  1080. #endif
  1081. if (ichInsert + 1 >= cchInsBlock) { /* Not enough room in the insertion block */
  1082. FlushInsert();
  1083. #ifdef KOREA
  1084. ichInsertSave = ichInsert; /* After flush, need to init ichInsertSave */
  1085. #endif
  1086. }
  1087. rgchInsert[ichInsert++] = chInsert = HIBYTE(wInsert);
  1088. chShow = HIBYTE(wShow);
  1089. }
  1090. else {
  1091. fDBCSChar = FALSE;
  1092. chInsert = LOBYTE(wInsert);
  1093. chShow = LOBYTE(wShow);
  1094. }
  1095. rgchInsert [ ichInsert++ ] = LOBYTE(wInsert);
  1096. #else
  1097. rgchInsert [ ichInsert++ ] = chInsert;
  1098. #endif /* DBCS */
  1099. /* NOTE: we only affect the para cache if the char inserted is Eol/chSect.
  1100. We explicitly invalidate in this case below; otherwise, no invalidation
  1101. is necessary */
  1102. /* The following test works because chEol and chSect is not in
  1103. the DBCS range. */
  1104. if ( (chInsert == chEol) || (chInsert == chSect) )
  1105. { /* Add a paragraph run to the scratch file */
  1106. struct PAP papT;
  1107. /* Must invalidate the caches */
  1108. vdocParaCache = vfli.doc = docNil;
  1109. #ifdef DBCS
  1110. Assert(!fDBCSChar); /* Of course, you can't be too careful */
  1111. #endif /* DBCS */
  1112. /* Get props for new para mark */
  1113. /* NOTE: Under the new world, CachePara does not expect to ever */
  1114. /* see an Eol in the insertion piece */
  1115. ichInsert--;
  1116. CachePara( docCur, cpInsert + cchInsBlock );
  1117. papT = vpapAbs;
  1118. ichInsert++;
  1119. #ifdef DEBUG
  1120. if (wwdCurrentDoc.fEditHeader || wwdCurrentDoc.fEditFooter)
  1121. {
  1122. Assert( papT.rhc != 0 );
  1123. }
  1124. #endif
  1125. /* Write insert buf out to the scratch file */
  1126. EndInsert();
  1127. /* Add run for new para properties to the scratch file */
  1128. AddRunScratch( &vfkpdParaIns,
  1129. &papT,
  1130. vppapNormal,
  1131. ((CchDiffer( &papT, &vpapPrevIns, cchPAP ) == 0) &&
  1132. (vfkpdParaIns.brun != 0)) ? -cchPAP : cchPAP,
  1133. fcMacPapIns = (**hpfnfcb)[fnScratch].fcMac );
  1134. blt( &papT, &vpapPrevIns, cwPAP );
  1135. /* Add a new insertion piece to the doc and we're ready to go again */
  1136. InvalidateCaches( docCur );
  1137. FBeginInsert();
  1138. mdInsUpd = mdInsUpdWhole; /* Must update the whole screen */
  1139. }
  1140. else if ( vfSuperIns && (chInsert != chNewLine) && (chInsert != chTab) &&
  1141. (chInsert != chNRHFile ) && (chInsert != chReturn) &&
  1142. !vfInsFontTooTall )
  1143. { /* We can do a superfast insert of this char */
  1144. ClearInsertLine();
  1145. #ifdef DBCS
  1146. /* Because chShow contains the first byte of a DBCS character,
  1147. even when it is a DBCS character, the following call
  1148. to DxpFromCh() is OK. */
  1149. #ifdef KOREA
  1150. if (fDBCSChar)
  1151. dxpCh = DxpFromCh(wShow, FALSE);
  1152. else
  1153. dxpCh = DxpFromCh(chShow, FALSE);
  1154. #else
  1155. dxpCh = DxpFromCh( chShow, FALSE );
  1156. #endif
  1157. if( dxpCh > 0 ){
  1158. // Maybe it's no need so marked off, by chienho
  1159. #if defined(TAIWAN) || defined(KOREA) || defined(PRC)
  1160. // dxpCh *= IsDBCSLeadByte(chShow) ? 2 : 1;
  1161. #else
  1162. dxpCh *= IsDBCSLeadByte(chShow) ? 2 : 1;
  1163. #endif
  1164. ScrollCurWw( prcScroll, dxpCh, 0 );
  1165. }
  1166. TextOut( wwdCurrentDoc.hDC,
  1167. vxpIns + 1,
  1168. vypBaseIns - vfmiScreen.dypBaseline,
  1169. (LPSTR) &rgchInsert[ichInsertSave],
  1170. dcchBlted = fDBCSChar ? 2 : 1 );
  1171. #ifdef KOREA /* 90.12.28 sangl */
  1172. if ( IsInterim )
  1173. { unsigned kc;
  1174. int dxpdiff;
  1175. SetBkMode( wwdCurrentDoc.hDC, 2); /* Set to OPAQUR mode */
  1176. do { DrawInsertLine();
  1177. // while ( ((kc=KcInputNextHan()) < 0xA1) || (kc>0xFE) );
  1178. while ( (((kc=KcInputNextHan()) < 0x81) || (kc>0xFE)) && (kc != VK_MENU)); // MSCH bklee 12/22/94
  1179. if(kc == VK_MENU) return mdInsUpdLines;
  1180. rgchInsert[ichInsertSave] = kc;
  1181. rgchInsert[ichInsertSave+1] = GetDBCSsecond();
  1182. ClearInsertLine();
  1183. wShow = (kc<<8) + rgchInsert[ichInsertSave+1];
  1184. prcScroll->left += dxpCh; /* New left start of rect */
  1185. dxpdiff = -dxpCh; /* Save last dxpCh to go back */
  1186. dxpCh = DxpFromCh(wShow, FALSE); /* Get dxpCh of curr interim */
  1187. dxpdiff += dxpCh;
  1188. if (dxpdiff < 0)
  1189. prcScroll->left += dxpdiff;
  1190. ScrollCurWw(prcScroll, dxpdiff, 0);
  1191. TextOut( wwdCurrentDoc.hDC,
  1192. vxpIns + 1,
  1193. vypBaseIns - vfmiScreen.dypBaseline,
  1194. (LPSTR)&rgchInsert[ichInsertSave], 2);
  1195. // } while (LOBYTE(HIWORD(vmsgLast.lParam))==0xF0); /* End of If Hangeul */
  1196. } while (fInterim || LOBYTE(HIWORD(vmsgLast.lParam))==0xF0); // MSCH bklee 12/22/94
  1197. WasInterim = 1;
  1198. IsInterim = 0;
  1199. SetBkMode(wwdCurrentDoc.hDC, 1); /* Reset to TRANS mode */
  1200. }
  1201. #endif /* KOREA */
  1202. vcchBlted += dcchBlted;
  1203. #else
  1204. /* Because chShow contains the first byte of a DBCS character,
  1205. even when it is a DBCS character, the following call
  1206. to DxpFromCh() is OK. */
  1207. if ((dxpCh = DxpFromCh( chShow, FALSE )) > 0)
  1208. ScrollCurWw( prcScroll, dxpCh, 0 );
  1209. TextOut( wwdCurrentDoc.hDC,
  1210. vxpIns + 1,
  1211. vypBaseIns - vfmiScreen.dypBaseline,
  1212. (LPSTR) &chShow,
  1213. 1 );
  1214. vcchBlted++;
  1215. #endif /* DBCS */
  1216. vxpCursLine = (vxpIns += dxpCh);
  1217. DrawInsertLine();
  1218. /* Decide whether we have affected the next dl with this insertion */
  1219. if ( vxpIns >= vxpMacIns )
  1220. mdInsUpd = mdInsUpdLines;
  1221. else if (!FImportantMsgPresent())
  1222. { /* No chars waiting; check for optional line update (word wrap) */
  1223. if ((dl = vdlIns) < wwdCurrentDoc.dlMac - 1)
  1224. {
  1225. vfli.doc = docNil;
  1226. FormatInsLine(); /* Update vfli for vdlIns */
  1227. mdInsUpd = (vfli.cpMac != (**wwdCurrentDoc.hdndl) [dl + 1].cpMin) ?
  1228. (FImportantMsgPresent() ? mdInsUpdNextChar : mdInsUpdOneLine) :
  1229. mdInsUpdNothing;
  1230. }
  1231. }
  1232. else
  1233. /* Don't update; pay attention to the next character */
  1234. mdInsUpd = mdInsUpdNextChar;
  1235. }
  1236. else if (vfSuperIns)
  1237. { /* In SuperInsMode but have a char we can't handle in SuperIns mode */
  1238. mdInsUpd = (vfInsFontTooTall) ? mdInsUpdWhole : mdInsUpdLines;
  1239. }
  1240. else
  1241. { /* Non-superfast insertion; update line if we have to */
  1242. vfli.doc = docNil;
  1243. FormatInsLine(); /* Update vfli for vdlIns */
  1244. /* Do the update only if: (1) the selection is no longer on
  1245. the current line OR (2) No char is waiting */
  1246. #ifdef KOREA
  1247. mdInsUpd = mdInsUpdLines;
  1248. #else
  1249. mdInsUpd = ( (selCur.cpFirst < vfli.cpMin) ||
  1250. (selCur.cpFirst >= vfli.cpMac) ||
  1251. !FImportantMsgPresent() ) ? mdInsUpdLines : mdInsUpdNextChar;
  1252. #endif
  1253. }
  1254. Scribble( 10, mdInsUpd + '0' );
  1255. return mdInsUpd;
  1256. }
  1257. void NEAR FlushInsert()
  1258. { /* Flush the insert buffer to the scratch file. Insert a piece (ahead of
  1259. the QD insertion piece) that points to the characters flushed to the
  1260. scratch file. Adjust CP's for the addition of the new scratch file
  1261. piece. */
  1262. #ifdef DBCS
  1263. /* The DBCS version of FlushInsert() is almost identical to the regular
  1264. version, except it allows to insert an insertion block with one byte
  1265. less than full. This allows us to assume that the piece boundary aligns
  1266. with the DBCS boundary. */
  1267. typeFC fc = FcWScratch( rgchInsert, ichInsert );
  1268. int dcpDel;
  1269. #if WINVER >= 0x300
  1270. if (!vfSysFull)
  1271. /* The "tape dispenser bug replication method" has shown that
  1272. holding down a key for 64k presses will cause FcWScratch()
  1273. to run out of scratch-file space and fail. If we go ahead
  1274. with the Replacement we'll corrupt the piece table, so we
  1275. delicately avoid that problem 3/14/90..pault */
  1276. #endif
  1277. {
  1278. Assert( cchInsBlock - ichInsert <= 1);
  1279. Repl1( docCur, cpInsert, (typeCP) 0, fnScratch, fc, (typeFC) ichInsert );
  1280. cpLimInserted += ichInsert;
  1281. vfInvalid = fFalse;
  1282. vpedlAdjustCp = (struct EDL *) 0;
  1283. AdjustCp( docCur, cpInsert += ichInsert, (typeCP) (dcpDel = cchInsBlock - ichInsert),
  1284. (typeCP) cchInsBlock );
  1285. if (vpedlAdjustCp)
  1286. vpedlAdjustCp->dcpMac += (cchInsBlock - dcpDel);
  1287. }
  1288. #else
  1289. typeFC fc = FcWScratch( rgchInsert, cchInsBlock );
  1290. #if WINVER >= 0x300
  1291. if (!vfSysFull)
  1292. /* The "tape dispenser bug replication method" has shown that
  1293. holding down a key for 64k presses will cause FcWScratch()
  1294. to run out of scratch-file space and fail. If we go ahead
  1295. with the Replacement we'll corrupt the piece table, so we
  1296. delicately avoid that problem 3/14/90..pault */
  1297. #endif
  1298. {
  1299. Assert( ichInsert == cchInsBlock );
  1300. Repl1( docCur, cpInsert, (typeCP) 0, fnScratch, fc, (typeFC) cchInsBlock );
  1301. cpLimInserted += cchInsBlock;
  1302. vfInvalid = fFalse;
  1303. vpedlAdjustCp = (struct EDL *) 0;
  1304. AdjustCp( docCur, cpInsert += cchInsBlock, (typeCP) 0, (typeFC) cchInsBlock );
  1305. if (vpedlAdjustCp)
  1306. vpedlAdjustCp->dcpMac += cchInsBlock;
  1307. }
  1308. #endif /* DBCS */
  1309. vfInvalid = fTrue;
  1310. ichInsert = 0;
  1311. }
  1312. int NEAR XpValidateInsertCache( rgdxp )
  1313. int *rgdxp;
  1314. { /* Validate the contents of the insert width cache, consisting of:
  1315. (parm) rgdxp: table of widths of chars on the current insert
  1316. line (vdlIns) as last DisplayFli'd
  1317. (global) vidxpInsertCache: -1 if invalid, index of current
  1318. insert point otherwise
  1319. (return value) xpMac: Mac pixel used on the insert line
  1320. */
  1321. int xpMac;
  1322. Assert( vidxpInsertCache == -1 );
  1323. vfli.doc = docNil; /* Force FormatLine to act */
  1324. /* Assert that FormatLine results will match screen contents */
  1325. Assert( (**wwdCurrentDoc.hdndl)[vdlIns].fValid );
  1326. /* Build vfli from insert line, extract cache info */
  1327. FormatInsLine();
  1328. blt( vfli.rgdxp, rgdxp, ichMaxLine );
  1329. xpMac = umin( vfli.xpRight + xpSelBar, wwdCurrentDoc.xpMac );
  1330. Assert( vcchBlted == 0);
  1331. vidxpInsertCache = (int) (cpInsert + ichInsert - vfli.cpMin);
  1332. Assert( vidxpInsertCache >= 0 && vidxpInsertCache < vfli.cpMac - vfli.cpMin);
  1333. return xpMac;
  1334. }
  1335. void NEAR DelChars( cp, cch )
  1336. typeCP cp;
  1337. int cch;
  1338. { /* Delete cch characters at cp in docCur.
  1339. We expect the request to be as results from repeated backspaces
  1340. or forward deletes (not both); that is, the whole range extends
  1341. backwards from (cpInsert + ichInsert) (non-inclusive) or forward from
  1342. (cpInsert + cchInsBlock) (inclusive).
  1343. We do not mark the vfli cache invalid, for speed.
  1344. The Fast insert stuff will mark it invalid when it needs to.
  1345. */
  1346. int cchNotInQD;
  1347. typeCP cpUndoAdd;
  1348. int cchNewDel=0;
  1349. Assert( (cp == cpInsert + cchInsBlock) || /* Fwd Deletes */
  1350. (cp + cch == cpInsert + ichInsert)); /* Backsp */
  1351. cchNotInQD = cch - ichInsert;
  1352. if (cp + cchNotInQD == cpInsert)
  1353. { /* BACKSPACE */
  1354. if (cchNotInQD <= 0)
  1355. { /* All deleted chars were in the QD buffer */
  1356. ichInsert -= cch;
  1357. /* Do not mark the para cache invalid -- we have not affected
  1358. the para cache world, since there are never chSect/chEol in
  1359. the QD buffer, and we have not adjusted cp's */
  1360. return;
  1361. }
  1362. else
  1363. { /* Backspacing before the QD buffer */
  1364. ichInsert = 0;
  1365. if (cpStart > cp)
  1366. {
  1367. cpUndoAdd = cp0;
  1368. cchNewDel = cpStart - cp;
  1369. vuab.cp = cpStart = cp;
  1370. /* cpStart has moved, and the count of cp's inserted has not
  1371. changed -- we must adjust cpLimInserted */
  1372. cpLimInserted -= cchNewDel;
  1373. }
  1374. cpInsert -= cchNotInQD;
  1375. }
  1376. } /* End of if backspacing */
  1377. else
  1378. { /* FORWARD DELETE */
  1379. typeCP dcpFrontier = (cp + cch - cpLimInserted);
  1380. if (dcpFrontier > 0)
  1381. {
  1382. cpUndoAdd = CpMacText( docUndo );
  1383. cchNewDel = (int) dcpFrontier;
  1384. cpLimDeleted += dcpFrontier;
  1385. }
  1386. cchNotInQD = cch;
  1387. }
  1388. /* Now we have: cchNewDel - chars deleted beyond previous limits
  1389. (cpStart to cpLimDeleted)
  1390. cpUndoAdd - where to add deleted chars to Undo doc
  1391. (only set if cchNewDel > 0)
  1392. cchNotInQD - chars deleted outside QD buffer */
  1393. if (cchNotInQD > cchNewDel)
  1394. /* Deleting chars previously inserted during this AlphaMode session */
  1395. cpLimInserted -= (cchNotInQD - cchNewDel);
  1396. /* Add the newly deleted stuff to the UNDO document.
  1397. We find the { fn, fc } of the deleted char(s)
  1398. so we can take advantage of Replace's optimizations
  1399. wrt combining adjacent pieces (if the deletion is all one piece).
  1400. */
  1401. if (cchNewDel > 0)
  1402. {
  1403. struct PCTB **hpctb=(**hpdocdod)[ docCur ].hpctb;
  1404. int ipcd=IpcdFromCp( *hpctb, cp );
  1405. struct PCD *ppcd=&(*hpctb)->rgpcd [ipcd];
  1406. int fn=ppcd->fn;
  1407. typeFC fc=ppcd->fc;
  1408. Assert( ppcd->fn != fnNil && (ppcd+1)->cpMin >= cp );
  1409. if (bPRMNIL(ppcd->prm) && (cchNewDel <= (ppcd+1)->cpMin - cp))
  1410. { /* Deletion is all within one piece */
  1411. Replace( docUndo, cpUndoAdd, cp0, fn, fc + (cp - ppcd->cpMin),
  1412. (typeFC) cchNewDel );
  1413. }
  1414. else
  1415. {
  1416. ReplaceCps( docUndo, cpUndoAdd, cp0, docCur, cp,
  1417. (typeCP) cchNewDel );
  1418. }
  1419. switch ( vuab.uac ) {
  1420. default:
  1421. Assert( FALSE );
  1422. break;
  1423. case uacDelNS:
  1424. vuab.dcp += cchNewDel;
  1425. break;
  1426. case uacReplNS:
  1427. vuab.dcp2 += cchNewDel;
  1428. break;
  1429. }
  1430. }
  1431. /* Remove deleted chars from the doc */
  1432. Replace( docCur, cp, (typeCP) cchNotInQD, fnNil, fc0, fc0 );
  1433. }
  1434. FUpdateOneDl( dl )
  1435. int dl;
  1436. { /* Update the display line dl. Mark dl+1 as invalid if, in the process
  1437. formatting dl, we discover that there is not a clean cp or
  1438. yp transition between the two lines (i.e. the ending yp or cp of dl
  1439. do not match the starting ones of dl+1).
  1440. Return TRUE iff we marked dl+1 invalid; FALSE otherwise
  1441. Starting cp & yp of dl+1 are adjusted as necessary */
  1442. register struct EDL *pedl=&(**(wwdCurrentDoc.hdndl))[dl];
  1443. int fUpdate=fFalse;
  1444. RECT rc;
  1445. vfli.doc = docNil;
  1446. FormatLine(docCur, pedl->cpMin, 0, wwdCurrentDoc.cpMac, flmSandMode);
  1447. pedl = &(**wwdCurrentDoc.hdndl) [dl + 1];
  1448. /* next line is invalid if it exists (<dlMac) and
  1449. not following in cp space or not following in yp space
  1450. */
  1451. if ( (dl + 1 < wwdCurrentDoc.dlMac) &&
  1452. (!pedl->fValid || (pedl->cpMin != vfli.cpMac) ||
  1453. (pedl->yp - pedl->dyp != (pedl-1)->yp)))
  1454. {
  1455. pedl->fValid = fFalse;
  1456. pedl->cpMin = vfli.cpMac;
  1457. pedl->yp = (pedl-1)->yp + pedl->dyp;
  1458. fUpdate = fTrue;
  1459. }
  1460. else
  1461. {
  1462. /* state is clean. Do not clear window dirty because more than one line may
  1463. have been made invalid earlier */
  1464. /* Tell Windows we made this region valid */
  1465. #if WINVER >= 0x300
  1466. /* Only actually USE pedl if it's be valid! ..pault 2/21/90 */
  1467. if (dl + 1 < wwdCurrentDoc.dlMac)
  1468. #endif
  1469. {
  1470. SetRect( (LPRECT) &rc, 0, wwdCurrentDoc.xpMac,
  1471. pedl->yp - pedl->dyp, pedl->yp );
  1472. ValidateRect( wwdCurrentDoc.wwptr, (LPRECT) &rc );
  1473. }
  1474. (--pedl)->fValid = fTrue;
  1475. }
  1476. DisplayFli(wwCur, dl, fFalse);
  1477. return fUpdate;
  1478. }
  1479. void NEAR FormatInsLine()
  1480. { /* Format line containing insertion point, using vdlIns as a basis
  1481. Assume vdlIns's cpMin has not changed */
  1482. FormatLine( docCur, (**wwdCurrentDoc.hdndl) [vdlIns].cpMin, 0,
  1483. wwdCurrentDoc.cpMac, flmSandMode );
  1484. /* Compensate for LoadFont calls in FormatLine so we don't have to set
  1485. vfTextBltValid to FALSE */
  1486. LoadFont( docCur, &vchpInsert, mdFontChk );
  1487. }
  1488. #ifdef DBCS
  1489. /* Get the second byte of a DBCS character using a busy loop. */
  1490. CHAR near GetDBCSsecond()
  1491. {
  1492. int kc;
  1493. CHAR chDBCS2;
  1494. BOOL fGotKey;
  1495. extern MSG vmsgLast;
  1496. fGotKey = FALSE;
  1497. do {
  1498. if ( FImportantMsgPresent() ) {
  1499. fGotKey = TRUE;
  1500. if ((kc=KcAlphaKeyMessage( &vmsgLast )) != kcNil) {
  1501. chDBCS2 = kc;
  1502. if (vmsgLast.message == WM_KEYDOWN) {
  1503. switch (kc) {
  1504. default:
  1505. GetMessage( (LPMSG) &vmsgLast, NULL, 0, 0 );
  1506. break;
  1507. case kcAlphaVirtual:
  1508. /* This means we can't anticipate the key's meaning
  1509. before translation */
  1510. chDBCS2 = '\0';
  1511. if (!FNonAlphaKeyMessage(&vmsgLast, FALSE)) {
  1512. GetMessage( (LPMSG)&vmsgLast, NULL, 0, 0 );
  1513. TranslateMessage( &vmsgLast );
  1514. }
  1515. break;
  1516. }
  1517. }
  1518. else {
  1519. if (kc < 0) {
  1520. chDBCS2 = '\0';
  1521. }
  1522. GetMessage( (LPMSG) &vmsgLast, NULL, 0, 0 );
  1523. }
  1524. }
  1525. else {
  1526. chDBCS2 = '\0';
  1527. }
  1528. }
  1529. } while (!fGotKey);
  1530. /* As long as we go through the DBCS conversion window, this
  1531. should not happen. */
  1532. Assert(chDBCS2 != '\0');
  1533. return chDBCS2;
  1534. }
  1535. #endif /* DBCS */