main.c
上传用户:xiaoan1112
上传日期:2013-04-11
资源大小:19621k
文件大小:17k
源码类别:

操作系统开发

开发平台:

Visual C++

  1. ;/*
  2. ; *                      Microsoft Confidential
  3. ; *                      Copyright (C) Microsoft Corporation 1991
  4. ; *                      All Rights Reserved.
  5. ; */
  6. #include <common.h>
  7. #include <filemgr.h>
  8. #include <text.h>
  9. #include <menus.h>
  10. #include <prot.h>
  11. #include <time.h>
  12. #include <direct.h>
  13. extern GlobalIdle(void);
  14. extern TOKEN Get_Identifier_Token(char far *identifier);
  15. extern void Shell_TTY_Out(char *str);
  16. extern void Get_CWD(char *);
  17. extern BOOL AddTask(char far *programname, char far *parameters,char far *defaulttitle,TOKEN properties);
  18. struct CountryBuffer {
  19.     int Date_Format;
  20.     char Currency_Symbol[5];
  21.     char Thousands_Sep[2];
  22.     char Decimal_Sep[2];
  23.     char Date_Sep[2];
  24.     char Time_Sep[2];
  25.     char Currency_Pos;
  26.     char Num_Decimals;
  27.     char Time_Format;
  28.     long Case_Mapping;
  29.     char Data_Sep[2];
  30.     char Reserved[10];
  31. } ;
  32. struct CountryBuffer NationData;
  33. MSG     msg;
  34. INST    ginst;
  35. INGD    gingd;
  36. INDV    gindv;
  37. BOOL    gisgraph = FALSE ;
  38. INCH    cinch;
  39. BOOL gfStillInitializing; /* used in allocs to bail if we're gonna toast */
  40. BOOL gfScreenModeChanged; /* used to restore screen in case we bail out early */
  41. BOOL gfSwapHandlerInstalled;
  42. char gStartUpDir[1+MAX_PATH];
  43. char gStartInDir[1+MAX_PATH];
  44. int gStartUpDirEnd; /* location where the NULL goes in the above name */
  45. BOOL gBeeps_On; /* Whether to have Beeps turned on or not on error */
  46. gBeeps_On = TRUE ;
  47. extern MENUINFO MainMenuBar;
  48. extern MENUINFO FileMgrMenuBar;
  49. extern BYTE ErrorCrit;
  50. extern VOID setmenubar(MENUINFO *amenu,PWND towind);
  51. extern BOOL GetInternationalData(void);
  52. extern void InstallSwapHandler(void) ;
  53. extern void     PrintHelpText(void);
  54. extern VOID SetUpExitToDos(void); /* see init.c */
  55. extern BOOL AsynchUpdateTreeList(void);
  56. VOID DeleteBatchFile(void);
  57. extern WND ViewWind;
  58. extern BOOL gMouseDown;
  59. extern BYTE gMouseX;    /* X value of last mouse-down */
  60. extern BYTE gMouseY;    /* Y value of last mouse-down */
  61. /* INTERNATIONALIZE HERE!
  62.  * We still don't have international am/pm symbols
  63. */
  64. /*
  65.  * sets up datestr to be in format ' 00-00-00 '
  66.  * sets up timestr to be in format ' 12:20 am '
  67.  *
  68.  * if force is not set, and time (minutes) has not changed, returns
  69.  * false and does not format strings.
  70.  * if force is set, formats strings and returns true
  71.  * if force is not set, and time has changed, formats strings and returns true
  72.  */
  73. #define NumToAsc(num,str) (temp=(num)/10, *(str++)=(char)((temp%10)+'0'), *(str++)=(char)((num)-temp*10+'0'))
  74. BOOL FAR Get_Date_and_Time_Strings(unsigned int theDate, unsigned int theTime,
  75.       char *datestr, char *timestr, BOOL force)
  76. {
  77.     static struct tm lasttime;
  78.     struct tm temptime, *newtime;
  79.     time_t long_time;
  80.     register int temp;
  81.     int date1, date2, date3;  /* for international date order */
  82.     if(!theDate && !theTime) {
  83. time(&long_time);
  84. newtime = localtime(&long_time);
  85.     } else {
  86. temptime.tm_year = 80 + (theDate>>0x09);
  87. temptime.tm_mon  = ((theDate>>0x05)&0x0f) - 1;
  88. temptime.tm_mday = theDate&0x1f;
  89. temptime.tm_hour = theTime>>0x0b;
  90. temptime.tm_min  = (theTime>>0x05)&0x3f;
  91. #if 0 /* We don't use the seconds */
  92. temptime.tm_sec  = 2*(theTime&0x1f);
  93. #endif
  94. newtime = &temptime;
  95. goto FormatDateAndTime;
  96.     }
  97.     if (force || (newtime->tm_min != lasttime.tm_min))
  98.     {
  99. lasttime = *newtime;
  100. FormatDateAndTime:
  101. if(datestr) {
  102.     if(NationData.Date_Format == 1) {
  103. date1 = newtime->tm_mday;
  104. date2 = newtime->tm_mon + 1;
  105. date3 = newtime->tm_year;
  106.     } else if(NationData.Date_Format == 2) {
  107. date1 = newtime->tm_year;
  108. date2 = newtime->tm_mon + 1;
  109. date3 = newtime->tm_mday;
  110.     } else {
  111. date1 = newtime->tm_mon + 1;
  112. date2 = newtime->tm_mday;
  113. date3 = newtime->tm_year;
  114.     }
  115.     NumToAsc(date1, datestr);
  116.     *(datestr++) = *NationData.Date_Sep;
  117.     NumToAsc(date2, datestr);
  118.     *(datestr++) = *NationData.Date_Sep;
  119.     NumToAsc(date3, datestr);
  120. }
  121. if(timestr) {
  122.     if(NationData.Time_Format&0x01) { /* A 24-hour clock */
  123. timestr[5] = ' ';
  124. NumToAsc(newtime->tm_hour, timestr);
  125.     } else { /* A 12-hour clock */
  126. temp = newtime->tm_hour;
  127. if(temp < 12) {
  128.     if(temp == 0)
  129. temp = 12;
  130.     timestr[5] = 'a';
  131. } else {
  132.     if(temp != 12)
  133. temp = temp - 12;
  134.     timestr[5] = 'p';
  135. }
  136. if((temp/10)>0)
  137.     *(timestr++) = (char) ((temp/10) + '0');
  138. else
  139.     *(timestr++) = (char) ' ';
  140. *(timestr++) = (char) ((temp%10) + '0');
  141.     }
  142.     *(timestr++) = *NationData.Time_Sep;
  143.     NumToAsc(newtime->tm_min, timestr);
  144. }
  145. return(TRUE);
  146.     } else {
  147.        return(FALSE);
  148.     }
  149. }
  150. /*
  151.  * draw the top title bar--
  152.  */
  153. VOID FAR UpdateMainTitleBar(char *szTitle)
  154. {
  155.     char *titlestring;
  156.     int i;
  157.     WORD len;
  158.     WORD titlestart;
  159.     char padded[100];
  160.  titlestring = szTitle ;
  161.     len = strlen(titlestring);
  162.     titlestart = axMac/2 - len/2;
  163.     for(i=0;i<axMac;i++)
  164.     {
  165. padded[i] = ' ';
  166.     }
  167.     FEnableMouseNest(FALSE);
  168.     TextOut(&MainWind,(RX) 0,(RY) 0, padded,titlestart,isaHilite);
  169.  TextOut(&MainWind,(RX) titlestart,0,titlestring,len,isaHilite);
  170.     TextOut(&MainWind,(RX) titlestart+len,(RY)0, padded,axMac-(titlestart+len),isaHilite);
  171.     if (gisgraph)
  172.     {
  173. if(CHEIGHT > SMALLHEIGHT)
  174. {
  175.      SetAreaPat(0);
  176.      SetLinePat(1);
  177.      SetColor(0,0x7FFF);
  178.      Move(0,CHEIGHT-1);
  179.      Draw((axMac)*CWIDTH,CHEIGHT-1);
  180. }
  181.     }
  182.     FEnableMouseNest(TRUE);
  183. }
  184. VOID FAR PauseBeforeScreenErase(VOID)
  185. {
  186. #ifndef NOLOADER
  187.     if(Get_KeyWord_Assignment(TK_SAVESTATE,TK_PAUSE) != TK_DISABLED)
  188.     {
  189. if (GET_WAIT_FLAG())
  190. {
  191.  /* clear out keyboard buffer */
  192.  while(kbhit())
  193. getch();
  194.  Shell_TTY_Out(szPressAKey);
  195.  /* wait for key to be hit */
  196.     while(!kbhit())
  197. ;
  198.  /* eat key */
  199.     getch();
  200. }
  201. Set_KeyWord_Assignment(TK_SAVESTATE,TK_PAUSE,TK_ENABLED);
  202.     }
  203. #endif
  204. }
  205. VOID ParseCommandLine(void)
  206. {
  207.     char far *commandline;
  208.     char lastfound=0;
  209.     char tstr[256], *szWhichRes;
  210.     TOKEN tkRes;
  211. #ifndef NOLOADER
  212.     if(GET_WAIT_FLAG())
  213. return;
  214. /*      We use the previous bytes to store pause flag status, a far pointer, etc
  215.  *      See loader.asm for exact details.
  216.  */
  217. commandline = GET_COMMAND_PTR()+9;
  218. #if 0
  219. printf("%d, ", *(commandline-2)) ;
  220. printf("%d, ", *(commandline-1)) ;
  221. printf("%d, ", *commandline) ;
  222. printf("%d, ", *(commandline+1)) ;
  223. printf("%d, ", *(commandline+2)) ;
  224. printf("%d, ", *(commandline+3)) ;
  225. printf("n") ;
  226. getchar() ;
  227. #endif
  228.     for( ; ; ++commandline) {
  229. switch(*commandline) {
  230. case(''):
  231. case('r'):
  232.     goto AllDone;
  233.     break;
  234. case('/'):
  235.     ++commandline;
  236.     switch(lastfound=(char)toupper(*commandline)) {
  237.     case 'T':
  238. Set_KeyWord_Assignment(TK_SAVESTATE, TK_SCREENMODE, TK_TEXT);
  239. break;
  240.     case 'G':
  241. Set_KeyWord_Assignment(TK_SAVESTATE, TK_SCREENMODE,TK_GRAPHICS);
  242. break ;
  243. #ifdef ERICLIKESBEEPCONTROL
  244.     case 'B' : // /BEEP
  245. Set_KeyWord_Assignment(TK_SAVESTATE, TK_BEEP, TK_ENABLED);
  246. break ;
  247.     case 'N' : // /NOBEEP
  248. Set_KeyWord_Assignment(TK_SAVESTATE, TK_BEEP, TK_DISABLED);
  249. break ;
  250. #else
  251.     case 'B' :
  252. Set_KeyWord_Assignment(TK_SAVESTATE, TK_FORCEMONO, TK_ENABLED);
  253. break ;
  254. #endif
  255. #ifdef SWAPMOUSESWITCH
  256.     case 'S' : // /SWAPMOUSE
  257. Set_KeyWord_Assignment(TK_SAVESTATE, TK_SWAPMOUSE,
  258. Get_KeyWord_Assignment(TK_SAVESTATE, TK_SWAPMOUSE)
  259. == TK_DISABLED ? TK_ENABLED : TK_DISABLED);
  260. break ;
  261. #endif
  262. #if 0
  263.     case '?' : // /HELP
  264.     case 'H' :
  265. #endif
  266.     default  :
  267. PrintHelpText();
  268. SetUpExitToDos();
  269. exit(0);
  270.     }
  271.     break;
  272. case(':'):
  273.     ++commandline;
  274.     switch(lastfound) {
  275.     case 'G':
  276.     case 'T':
  277. switch(toupper(*commandline)) {
  278. case 'L':
  279.     tkRes = TK_LOWRES;
  280.     goto MakeKeyword;
  281. case 'M':
  282.     tkRes = TK_MEDIUMRES;
  283.     goto MakeKeyword;
  284. case 'H':
  285.     tkRes = TK_HIGHRES;
  286.     goto MakeKeyword;
  287. MakeKeyword:
  288.     strfcpy(tstr, Get_Token_Identifier(tkRes));
  289.     for(szWhichRes=tstr; *szWhichRes; ++szWhichRes)
  290. /*do nothing */ ;
  291.     for(++commandline; *commandline>='0' && *commandline<='9';
  292.     ++commandline)
  293. *(szWhichRes++) = *commandline;
  294.     *szWhichRes = '';
  295.     Set_KeyWord_Assignment(TK_SAVESTATE, TK_RESOLUTION,
  296.     Get_Identifier_Token(tstr));
  297.     break;
  298. default:
  299.     break;
  300. }
  301. break;
  302.     default:
  303. break;
  304.     }
  305.     lastfound = 0;
  306.     break;
  307. default:
  308.     break;
  309. }
  310.     }
  311. AllDone:
  312.     ;
  313. #endif
  314. }
  315. extern char far * cdecl GET_STARTUP_NAME(VOID);
  316. VOID FAR SetUpStartUpDirectory(VOID)
  317. {
  318. #ifndef NOLOADER
  319.     strfcpy(gStartUpDir,GET_STARTUP_NAME());
  320.     gStartUpDirEnd=FindLastComponent(gStartUpDir);
  321.     gStartUpDir[gStartUpDirEnd]= 0;
  322. #else
  323.     strcpy(gStartUpDir,".\");
  324. gStartUpDirEnd=2;
  325. #endif
  326. Get_CWD(gStartInDir);
  327. }
  328. extern char *gpszNonSwap ;
  329. /*
  330.  * This is where all background tasking is done, so it should
  331.  * be called often.
  332.  */
  333. VOID MainIdle(void)
  334. {
  335.    static  int     arbitrarycounter;
  336.    /* Add more idle procs here if required.
  337.    */
  338. #ifdef PROF
  339.    ClockOn();
  340. #endif
  341.    /* note we need to call both idles always!
  342.     * thus, the & must be & and not && so it
  343.     * won't short circuit!
  344.     */
  345.     if(gMouseDown && m_fPerformingViewFile()) {
  346. ViewWindProc(&ViewWind, WM_MOUSEIDLE, 1,
  347. ((DWORD)gMouseY<<24) | ((DWORD)gMouseX<<16));
  348.     }
  349.    if (FileMgrIdle() & StartProgramsIdle() & AsynchUpdateTreeList())
  350.    {
  351.       GlobalIdle(); /* Tell the world we're idle */
  352.    }
  353.    /*
  354.     * We poll the time to see if it changed. But we
  355.     * don't really need to do it all the time, so
  356.     * we use "arbitrarycounter" to determine if we should
  357.     * check to see if we should update it. Assumes we
  358.     * are idle 64k times a minute
  359.     */
  360.    if (arbitrarycounter++ == 0)
  361. MessageBar(gpszNonSwap, isaMenu,FALSE);
  362. #ifdef PROF
  363.    ClockOff();
  364. #endif
  365. fPollKeyboard=TRUE;
  366. }
  367. WORD gCnx = cnxNull;
  368. /*
  369.  * Called by CW during menu and dialog idle time
  370.  */
  371. WORD FARPUBLIC RspAppIdle(WORD cnx,DWORD Lparam)
  372. {
  373.     if(cnx == cnxDialog)
  374.     {
  375. PDLG    pdlg = (PDLG)LOWORD(Lparam);
  376. if (pdlg->pfnDlg != NULL)
  377. {
  378.      /* send dlmIdle to appropriate dialog proc */
  379.      (*pdlg->pfnDlg)(dlmIdle, 0, 0, 0, 0);
  380. }
  381.     }
  382.     gCnx = cnx;
  383.      /*
  384.       * do not idle when in a critcal dialog!
  385.       */
  386.      if( ErrorCrit == 0xFF)
  387.      {
  388. MainIdle();
  389.      }
  390.      gCnx = cnxNull;
  391.      return(rspContinue);
  392. }
  393. /*
  394.  * we don't use the standard argv handling, so why
  395.  * have it around?
  396.  */
  397. void cdecl _setargv(void)
  398. {
  399. }
  400. #if 0
  401. void cdecl _setenvp(void)
  402. {
  403. static char * foo;
  404. foo = environ;
  405. unlink("foo");
  406. }
  407. #endif
  408. /* WARNING
  409.  * this is a replacement for the C call malloc. This SHOULD NEVER BE
  410.  * CALLED IN YOUR CODE! This function is called at startup by
  411.  * C-runtime to setup the environment. Since we don't want to carry
  412.  * around a bunch of code we don't use, we just use our own allocation
  413.  * Note that this memory is never freed! This is very important, since
  414.  * the freework function can tromp
  415.  * The real malloc sucks in about .5k of code
  416.  */
  417. void * cdecl malloc(unsigned int s)
  418. {
  419. return(PbAllocWork(s));
  420. }
  421. BOOL gfEarlyExit = FALSE ;
  422. extern Dos_Version(void);
  423. void VersionCheck(void) 
  424. {
  425. /* Perform version check!! We use the new "int 2f" issued by the BIOS
  426.  * to swap disks on a single floppy system -- "A:", "B:" on 1 physical drive
  427.  */
  428. if (Dos_Version() < MIN_MAJOR_VERSION)
  429. {
  430. Shell_TTY_Out(szIncorrectDosVersion) ;
  431. gfEarlyExit = TRUE ;
  432. DoExit() ;
  433. }
  434. }
  435. extern WORD GetLastScanCode(void);
  436. /*
  437.  * Looks for '!' signature in the ROM, followed 18 bytes later by 
  438.  * '01' which is the ROM BIOS version number.  
  439.  * Thus, this will only detect Tandy's with version 1.0 ROM.
  440.  */
  441. #define IsTandy1000 ( (*((BYTE FAR *)0xf000c000L) == 0x21) && (*((WORD FAR *)0xf000c012L) == 0x3130))
  442. /*
  443.  * The Tandy 1000 returns some strange keyboard messages, so we have to
  444.  * trap them and change them to the correct messages.  GetLastScanCode
  445.  * helps us determine what the correct message is, but it will return
  446.  * useless values if a modifier key is changed, so we have to store the
  447.  * last useful value in wSaveScanCode.
  448.  */
  449. VOID FAR PASCAL Tandy1000KeyboardHook(WORD message, WORD wParam, DWORD lParam)
  450. {
  451.     static WORD wSaveScanCode = 0;
  452.     WORD wLastScanCode;
  453. #if 0
  454.     char buf[80];
  455.     if(message == WM_CHAR)
  456. com1("nWM_CHAR    ");
  457.     else if(message == WM_KEYUP)
  458. com1("nWM_KEYUP   ");
  459.     else if(message == WM_KEYDOWN)
  460. com1("nWM_KEYDOWN ");
  461.     else {
  462. sprintf(buf, "n%-10d ", message);
  463. com1(buf);
  464.     }
  465.     sprintf(buf, "%04x 0x%04x 0x%04x ", wParam, HIWORD(lParam),
  466.     GetLastScanCode()&0xff7f);
  467.     com1(buf);
  468.     if(message==WM_CHAR && !(wParam&0xff00)) {
  469. buf[0] = LOBYTE(wParam);
  470. buf[1] = '';
  471. com1(buf);
  472.     }
  473. #endif
  474.     if(message == WM_CHAR) {
  475. switch(wParam) {
  476. case(VK_HOME):
  477.     wLastScanCode = GetLastScanCode()&0x7f;
  478.     if(wLastScanCode == 0x47 || wLastScanCode == 0x58)
  479. wSaveScanCode = wLastScanCode;
  480.     if(wSaveScanCode == 0x47)
  481. wParam = '\';
  482.     break;
  483. case(VK_LEFT):
  484.     wLastScanCode = GetLastScanCode()&0x7f;
  485.     if(wLastScanCode == 0x4b || wLastScanCode == 0x2b)
  486. wSaveScanCode = wLastScanCode;
  487.     if(wSaveScanCode == 0x4b)
  488. wParam = '|';
  489.     break;
  490. case(VK_UP):
  491.     wLastScanCode = GetLastScanCode()&0x7f;
  492.     if(wLastScanCode == 0x48 || wLastScanCode == 0x29)
  493. wSaveScanCode = wLastScanCode;
  494.     if(wSaveScanCode == 0x48)
  495. wParam = '~';
  496.     break;
  497. case(VK_DOWN):
  498.     wLastScanCode = GetLastScanCode()&0x7f;
  499.     if(wLastScanCode == 0x50 || wLastScanCode == 0x4a)
  500. wSaveScanCode = wLastScanCode;
  501.     if(wSaveScanCode == 0x50)
  502. wParam = '`';
  503.     break;
  504. case('-'):
  505.     wLastScanCode = GetLastScanCode()&0x7f;
  506.     if(wLastScanCode == 0x58 || wLastScanCode == 0x0c)
  507. wSaveScanCode = wLastScanCode;
  508.     if(wSaveScanCode == 0x58)
  509. wParam = VK_HOME;
  510.     break;
  511. }
  512.     }
  513.     InsertKeyboardMessage(message, wParam, lParam);
  514. }
  515. #ifdef HASHHITTEST
  516. char b1[80];
  517. extern int ghashhits;
  518. extern int ghashmisses;
  519. extern int ghashnotpresent;
  520. extern int gnohashnotpresent;
  521. #endif
  522. extern VOID Do_Read_Ini_File(void);
  523. /*
  524. **                              Main program
  525. */
  526. void cdecl main(int argc, char *argv[])
  527. {
  528. UnReferenced(argc) ;
  529. UnReferenced(argv) ;
  530. /* Get information on the country we're in... */
  531. GetInternationalData();
  532. /* In case we bail out because of low memory situations, we want to
  533.  * restore the screen to appropriate state before quitting in case we
  534.  * modified the screen mode.
  535.  */
  536. gfScreenModeChanged = FALSE;
  537. /* The following field is used to determine whether to bail out or not in
  538.  * a low memory situation. If we run out of memory when we are initializing
  539.  * we will bail out.
  540.  */
  541. gfStillInitializing = TRUE;
  542. /* used to de-install swap handler on exitting the shell */
  543. gfSwapHandlerInstalled = FALSE ;
  544. VersionCheck() ;
  545. SetUpStartUpDirectory();
  546. /*
  547.  *  parse the shell.ini file
  548.  */
  549. Do_Read_Ini_File();
  550. /* if we are returning from a program, we must pause before
  551.  * we initialize the screen so the user can read the output
  552.  * of the last program
  553.  */
  554. PauseBeforeScreenErase();
  555. if (!InitializeShell())
  556.     DoExit();
  557.     //if(IsTandy1000) check is disfunctional, so we used an ini switch
  558. if(Get_KeyWord_Assignment(TK_SAVESTATE,TK_TANDY1000) == TK_ENABLED)
  559. HookKeyboardMessage(TRUE, Tandy1000KeyboardHook);
  560.    /*  Allocate memory for the OutOfMemory Dialog Box HCAB structure now.
  561. * When we are actually, out of memory, we may not be able to allocate
  562. * enuf memory to put up the dialog box. This way, we are guaranteed to
  563. * atleast be able to say: "Out Of Memory" in a neat dialog box!
  564. */
  565. if (!AllocateHcabForOutOfMem())
  566. DoExit();
  567. /* Set up the collating table for sorts to be done later! */
  568. SetCollatingTable() ;
  569. /* If we have to use the collating sort, set sort functions to the
  570.  * collating sorts!
  571.  */
  572. if (!FDoQuickCompare())
  573. {
  574. SortFnArr[SORT_NAME] = name_cmp ;
  575. SortFnArr[SORT_EXT]  = ext_cmp ;
  576. /* This is the variable that is used to call the sort function! Update
  577.  * it correctly.
  578.  */
  579. if (*SortCmp == quick_name_cmp)
  580. {
  581. *SortCmp = name_cmp ;
  582. }
  583. else if (*SortCmp == quick_ext_cmp)
  584. {
  585. *SortCmp = ext_cmp ;
  586. }
  587. }
  588. InstallSwapHandler() ;
  589. /*
  590.  * WARNING taskmaninit must happen first!
  591.  */
  592. DeleteBatchFile();
  593. gfSwapHandlerInstalled = TRUE ;
  594. gfStillInitializing = FALSE;
  595. #ifdef HASHHITTEST
  596. ErrorCrit = 34; 
  597. itoa(ghashhits, b1, 10);
  598. strcat(b1, "n");
  599. itoa(ghashmisses, b1+strlen(b1), 10);
  600. strcat(b1, "n");
  601. itoa(gnohashnotpresent, b1+strlen(b1), 10);
  602. ShellMessageBox("HASH RESULTS", b1);
  603. ErrorCrit = 0xFF;
  604. #endif  
  605. /*
  606.  *      Handle messages (keyboard,mouse)
  607.  */
  608. MainIdle();
  609. while (1)
  610. {
  611.      if (PeekMessage(&msg))
  612.      {
  613.    DispatchMessage(&msg);
  614.      }
  615.      else
  616.      {
  617. MainIdle();
  618.      }
  619.      fPollKeyboard=TRUE;
  620. }
  621.  }