home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / cenvi23.zip / KEYPUSH.LIB < prev    next >
Text File  |  1995-09-11  |  17KB  |  452 lines

  1. // KeyPush.lib - PM routines to control, or mimic, the pushing of
  2. // ver.2         keys on the keyboard.  This is one method of controlling
  3. //               windows applications.  The functions in this library work
  4. //               by sending keyboard messages to the focus window as if
  5. //               the key messages were actually being sent by Windows.
  6. //
  7. //**** KeyPushFocusID(): Select focus window specification for this library
  8. // SYNTAX: int KeyPushFocusID(NULL)   // this is the default
  9. //         int KeyPushFocusID(string TopLevelTitle[,TempMakeActive])
  10. //         int KeyPushFocusID(int TopLevelHandle[,TempMakeActive])
  11. //         int KeyPushFocusID(int FocusWindowHandle)
  12. // WHERE: NULL: if NULL or 0 then will always send to the currently active focus window
  13. //        TopLevelTitle: ascii string - will send to focus window of this top-level window
  14. //        TopLevelHandle: handle for top-level window - will send to focus window of this top-level window
  15. //        FocusWindowHandle: will send directly to this window handle
  16. //        TempMakeActive: This window (or top-level window) for this application
  17. //                        must be the active window while the keystrokes are
  18. //                        sent, and will temporarily be made active.  The default
  19. //                        is TRUE for TopLevelTitle and TopLevelHandle methods, else
  20. //                        this doesn't apply and does not switch active window.
  21. // RETURN: Return window that would get focus NOW according to this setting, which
  22. //         may be NULL if this setting wouldn't work
  23. // NOTE: For TopLevelTitle and TopLevelHandle methods, these library routines
  24. //       may need to temporarily alter the activation of different windows if
  25. //       you don't specify TempMakeActive=False, which will look messy if the
  26. //       window you're sending to is not currently the active window.  In these
  27. //       situations, or if you're sending lots of KeyPushxxx messages, you may
  28. //       want to make the application active first or get the FocusWindowHandle
  29. //       if the window won't change.  For top level windows where this is not
  30. //       TempMakeActive is not given or is True, then will not make the application
  31. //       active but will only send to sub-window that last had active focus.
  32. //
  33. //
  34. //**** KeyStroke(): Press and release a key or combination of keys
  35. // SYNTAX: int KeyStroke([Holdkey1,HoldKey2,HoldKey3...,]byte Character)
  36. //         int KeyStroke([Holdkey1,HoldKey2,HoldKey3...,]int VirtualKeyCode)
  37. //         int KeyStroke([Holdkey1,HoldKey2,HoldKey3...,]string KeyString)
  38. // WHERE: Holdkey...: mimic that these keys are pressed before KeyCode or KeyString, and then
  39. //                    will press and release KeyCode or KeyString, and then will release
  40. //                    HoldKeys in reverse order.
  41. //        Character: ascii character to send
  42. //        VirtualKeyCode: one of the VK_ key codes (see below)
  43. //        KeyString: Ascii string to send
  44. // RETURN: Return handle keys were sent to; 0 if no handle found
  45. // EXAMPLES: To press the 'S' key: KeyStroke('S');
  46. //           To type a sentence: KeyStroke("On top of Old Smokey!\n");
  47. //           To type Alt-F1: KeyStroke("VK_ALT,VK_F1);
  48. //           To simulate Ctl-Alt-R: KeyStroke(VK_CONTROL,VK_ALT,'R');
  49. //
  50. //
  51. //**** SpeedKeys(): Send character messages
  52. // SYNTAX: int SpeedKeys(string AsciiString[,DelayBetweenKeys])
  53. //         int SpeedKeys(byte Character[,DelayBetweenKeys])
  54. // WHERE: AsciiString: string of characters to send
  55. //        Character: single character to send
  56. //        DelayBetweenKeys: Approximate time, in milliseconds, to wait after
  57. //                          sending each key message
  58. // NOTE: Speed keys sends only WM_CHAR messages to an application and is much
  59. //       faster than KeyStroke(), but should only be used for regular ascii
  60. //       strings passed to applications that don't need to for each specific
  61. //       keystroke.  So, if KeyStroke() is too slow and you're entering a
  62. //       stretch of plain text, then use this function.
  63. //
  64. //
  65. //**** KeyDown(): Press down a key (no release yet)
  66. // SYNTAX: int KeyDown(int KeyCode)
  67. // WHERE: KeyCode: Virtual VK_ key or character key
  68. // RETURN: Return handle keys were sent to; 0 if no handle found
  69. //
  70. //
  71. //**** KeyUP(): Release a key (that has been pressed down)
  72. // SYNTAX: int KeyUP(int KeyCode)
  73. // WHERE: KeyCode: Virtual VK_ key or character key
  74. // RETURN: Return handle keys were sent to; 0 if no handle found
  75. //
  76. //
  77.  
  78. #include <WinMsg.lib>
  79. #include <GiveMem.lib>
  80. #include <WinTools.lib>
  81. #include <ScanCode.lib>
  82.  
  83. /*** Virtual key values *************************************************/
  84. #define VK_BUTTON1   0x01
  85. #define VK_BUTTON2   0x02
  86. #define VK_BUTTON3   0x03
  87. #define VK_BREAK     0x04
  88. #define VK_BACKSPACE 0x05
  89. #define VK_TAB       0x06
  90. #define VK_BACKTAB   0x07
  91. #define VK_NEWLINE   0x08
  92. #define VK_SHIFT     0x09
  93. #define VK_CTRL      0x0A
  94. #define VK_ALT       0x0B
  95. #define VK_ALTGRAF   0x0C
  96. #define VK_PAUSE     0x0D
  97. #define VK_CAPSLOCK  0x0E
  98. #define VK_ESC       0x0F
  99. #define VK_SPACE     0x10
  100. #define VK_PAGEUP    0x11
  101. #define VK_PAGEDOWN  0x12
  102. #define VK_END       0x13
  103. #define VK_HOME      0x14
  104. #define VK_LEFT      0x15
  105. #define VK_UP        0x16
  106. #define VK_RIGHT     0x17
  107. #define VK_DOWN      0x18
  108. #define VK_PRINTSCRN 0x19
  109. #define VK_INSERT    0x1A
  110. #define VK_DELETE    0x1B
  111. #define VK_SCRLLOCK  0x1C
  112. #define VK_NUMLOCK   0x1D
  113. #define VK_ENTER     0x1E
  114. #define VK_SYSRQ     0x1F
  115. #define VK_F1        0x20
  116. #define VK_F2        0x21
  117. #define VK_F3        0x22
  118. #define VK_F4        0x23
  119. #define VK_F5        0x24
  120. #define VK_F6        0x25
  121. #define VK_F7        0x26
  122. #define VK_F8        0x27
  123. #define VK_F9        0x28
  124. #define VK_F10       0x29
  125. #define VK_F11       0x2A
  126. #define VK_F12       0x2B
  127. #define VK_F13       0x2C
  128. #define VK_F14       0x2D
  129. #define VK_F15       0x2E
  130. #define VK_F16       0x2F
  131. #define VK_F17       0x30
  132. #define VK_F18       0x31
  133. #define VK_F19       0x32
  134. #define VK_F20       0x33
  135. #define VK_F21       0x34
  136. #define VK_F22       0x35
  137. #define VK_F23       0x36
  138. #define VK_F24       0x37
  139. #define VK_ENDDRAG   0x38
  140. #define VK_MENU      VK_F10
  141.  
  142. // define a table of known scan codes
  143. gVK_ScanCodes = {
  144.     0,   0,   0,   0,   0,0x0E,0x0F,0x0F,0x1C,0x2A,0x1D,0x38,   0,   0,   0,0x01,
  145.  0x39,0x49,0x51,0x4F,0x47,0x4B,0x48,0x4D,0x50,   0,0x52,0x43,   0,   0,0x1C,   0,
  146.  0x3B,0x3C,0x3D,0x3E,0x3F,0x40,0x41,0x42,0x43,0x44
  147. };
  148.  
  149.  
  150.  
  151. KeyPushFocusID(pFocusID,pTempMakeActive)
  152. {
  153.    gFocusIDIsTopLevel = False;
  154.    if ( !pFocusID ) {
  155.       gFocusID = 0;
  156.       gKPTempMakeActive = False;
  157.    } else if ( 0 != DataDimension(pFocusID) ) {
  158.       // find window based on string
  159.       if ( !(gFocusID = GetWindowHandle(pFocusID)) )
  160.          return 0;
  161.       gFocusIDIsTopLevel = True;
  162.    } else {
  163.       // determine if this is one of the top level windows
  164.       lEnum = WinBeginEnumWindows(HWND_DESKTOP);
  165.       while ( lChild = WinGetNextWindow(lEnum) ) {
  166.          if ( pFocusID == lChild ) {
  167.             gFocusIDIsTopLevel = True;
  168.             break;
  169.          }
  170.       }
  171.       WinEndEnumWindows(lEnum);
  172.       gFocusID = pFocusID;
  173.    }
  174.    gKPTempMakeActive = ( va_arg() < 2 ) ? True : pTempMakeActive ;
  175.  
  176.    // gFocusID parameter is set.  Return window handle as regular KeyPush calls would
  177.    KeyPushInitialize();
  178.    KeyPushTerminate();
  179.    return gKPFocusWindow;
  180. }
  181.  
  182.  
  183. KeyStroke(pKey1,pKey2,pKey3/*etc...*/)
  184. {
  185.    if ( KeyPushInitialize() ) {
  186.       lArgCount = va_arg();
  187.       // if more than one parameter, then hold down all but the last one
  188.       for ( lKeyC = 1; lKeyC < lArgCount; lKeyC++ )
  189.          KeyDown(va_arg(lKeyC-1));
  190.  
  191.       lKey = va_arg(lArgCount-1);
  192.       // Treat differently depending on whether Virtual Key Code, char, or string
  193.       if ( CMM_BYTE == DataType(lKey) ) {
  194.          if ( 1 == DataDimension(lKey) ) {
  195.             // send entire string one character at a time
  196.             for ( lIdx = 0; lKey[lIdx]; lIdx++ ) {
  197.                lScan = GetScanCode(lKey[lIdx]);
  198.                KeyDown(lKey[lIdx],lScan);
  199.                KeyUp(lKey[lIdx],lScan);
  200.             }
  201.          } else {
  202.             // send a single character out the port
  203.             lScan = GetScanCode(lKey);
  204.             KeyDown(lKey,lScan);
  205.             KeyUp(lKey,lScan);
  206.          }
  207.       } else {
  208.          // simply a virtual key code
  209.          KeyDown(lKey);
  210.          KeyUp(lKey);
  211.       }
  212.  
  213.       // if more than one parameter, then reverse release all but the last one
  214.       for ( lKeyC = 1; lKeyC < lArgCount; lKeyC++ )
  215.          KeyUp(va_arg(lArgCount-lKeyC-1));
  216.    }
  217.    KeyPushTerminate();
  218.    return gKPFocusWindow;
  219. }
  220.  
  221. #define WM_CHAR   0x007a
  222. #define WM_TRANSLATEACCEL 0x004b
  223.  
  224. /* WM_CHAR fs field bits */
  225. #define KC_CHAR         0x0001
  226. #define KC_VIRTUALKEY   0x0002
  227. #define KC_SCANCODE     0x0004
  228. #define KC_SHIFT        0x0008
  229. #define KC_CTRL         0x0010
  230. #define KC_ALT          0x0020
  231. #define KC_KEYUP        0x0040
  232. #define KC_PREVDOWN     0x0080
  233. #define KC_LONEKEY      0x0100
  234. #define KC_DEADKEY      0x0200
  235. #define KC_COMPOSITE    0x0400
  236. #define KC_INVALIDCOMP  0x0800
  237. #define KC_TOGGLE       0x1000
  238. #define KC_INVALIDCHAR  0x2000
  239. #define KC_DBCSRSRVD1   0x4000
  240. #define KC_DBCSRSRVD2   0x8000
  241.  
  242. gKPLatestKeyDown = FALSE; // True on call to key down, false on KeyUp
  243.  
  244. KeyDown(pKey)
  245. {
  246.    if ( KeyPushInitialize() ) {
  247.       // Save the current state of the 256-byte keyboard buffer
  248.       lKeyTable = GetKeyboardTable();
  249.  
  250.       gKPLatestKeyDown = TRUE;
  251.  
  252.       if ( CMM_BYTE == DataType(pKey) ) {
  253.          // pushing just a character
  254.          lScan = integer((1 < va_arg()) ? va_arg(1) : GetScanCode(pKey));
  255.          lfsflags = KC_CHAR | KC_SCANCODE | (lScan << 24);
  256.          lusch = integer(pKey);
  257.          lusvk = 0;
  258.       } else {
  259.          // pushing a virtual key
  260.          lfsflags = KC_VIRTUALKEY;
  261.          lusch = 0;
  262.          lusvk = pKey;
  263.          if ((lKeyTable[pKey] = (lKeyTable[pKey] | 0x80) ^ 1) & 0x01)
  264.             lfsflags |= KC_TOGGLE;
  265.          SetKeyboardTable(lKeyTable);
  266.          if ( pKey <= GetArraySpan(gVK_ScanCodes) && gVK_ScanCodes[pKey] ) {
  267.             // add scan code for virtual key
  268.             lfsflags |= KC_SCANCODE | (gVK_ScanCodes[pKey] << 24);
  269.          }
  270.       }
  271.  
  272.       if ( lKeyTable[VK_SHIFT] & 0x80 )
  273.          lfsflags |= KC_SHIFT;
  274.       if ( lKeyTable[VK_ALT] & 0x80 )
  275.          lfsflags |= KC_ALT;
  276.       if ( lKeyTable[VK_CTRL] & 0x80 )
  277.          lfsflags |= KC_CTRL;
  278.  
  279.       SendMessageAndAccelTable(lfsflags | (1 << 16),lusch | (lusvk << 16));
  280.    }
  281.    KeyPushTerminate();
  282.    return gKPFocusWindow;
  283. }
  284.  
  285. KeyUp(pKey)
  286. {
  287.    if ( KeyPushInitialize() ) {
  288.       // Save the current state of the 256-byte keyboard buffer
  289.       lKeyTable = GetKeyboardTable();
  290.  
  291.       // set some fsflags based on keys currently pressed
  292.       lfsflags = KC_KEYUP /*| KC_PREVDOWN*/;
  293.  
  294.       if ( CMM_BYTE == DataType(pKey) ) {
  295.          // pushing just a character
  296.          lScan = integer((1 < va_arg()) ? va_arg(1) : GetScanCode(pKey));
  297.          lfsflags |= KC_CHAR | KC_SCANCODE | (lScan << 24);
  298.          lusch = lScan << 8;
  299.          if ( (lKeyTable[VK_CTRL] & 0x80)  &&  isalpha(pKey) )
  300.             // convert to control character
  301.             lusch |= toupper(pKey) - 'A' + 1;
  302.          else
  303.             lusch |= pKey;
  304.          lusvk = 0;
  305.       } else {
  306.          // pushing a virtual key
  307.          lfsflags |= KC_VIRTUALKEY;
  308.          lusch = 0;
  309.          lusvk = pKey;
  310.          if ((lKeyTable[pKey] &= 0x7F) & 0x01);
  311.             lfsflags |= KC_TOGGLE;
  312.          SetKeyboardTable(lKeyTable);
  313.          if ( pKey <= GetArraySpan(gVK_ScanCodes) && gVK_ScanCodes[pKey] ) {
  314.             // add scan code for virtual key
  315.             lfsflags |= KC_SCANCODE | (gVK_ScanCodes[pKey] << 24);
  316.          }
  317.       }
  318.  
  319.       if ( lKeyTable[VK_SHIFT] & 0x80 )
  320.          lfsflags |= KC_SHIFT;
  321.       if ( lKeyTable[VK_ALT] & 0x80 )
  322.          lfsflags |= KC_ALT;
  323.       if ( lKeyTable[VK_CTRL] & 0x80 )
  324.          lfsflags |= KC_CTRL;
  325.  
  326.       if ( gKPLatestKeyDown )
  327.          lfsflags |= KC_LONEKEY;
  328.       gKPLatestKeyDown = FALSE;
  329.  
  330.       // send message to window that this key is being pressed
  331.       SendMessageAndAccelTable(lfsflags | (1 << 16),lusch | (lusvk << 16));
  332.    }
  333.    KeyPushTerminate();
  334.    return gKPFocusWindow;
  335. }
  336.  
  337. SpeedKeys(pAsciiString,pDelayBetweenCharacters)
  338. {
  339.    if ( KeyPushInitialize() ) {
  340.       if ( 1 == DataDimension(pAsciiString) ) { lChar = pAsciiString; }
  341.       else { lChar[1] = '\0'; lChar[0] = pAsciiString; }
  342.       for ( ; lChar[0]; lChar++ ) {
  343.          lParam1 = ((KC_CHAR | KC_LONEKEY)) | (1 << 16);
  344.          WinSendMsg(gKPFocusWindow,WM_CHAR,lParam1,lChar[0]);
  345.          if ( 1 < va_arg() )
  346.             suspend(pDelayBetweenCharacters);
  347.       }
  348.    }
  349.    KeyPushTerminate();
  350.    return gKPFocusWindow;
  351. }
  352.  
  353.  
  354. /***********************************************************
  355.  *** PRIVATE UTILITIES USED BY THE ABOVE PUBLIC ROUTINES ***
  356.  ***********************************************************/
  357.  
  358. gFocusID = 0;
  359. gFocusIDIsTopLevel = False; // set true if using Focus ID that is top-level window
  360. gKeyPushInitializeDepth = 0;  // keep track how many times recursively called
  361. gKPFocusWindow;  // KeyPushInitialize sets to window
  362. gKPSaveActiveWindow = 0;
  363. gKPTempMakeActive = True;
  364.  
  365. KeyPushInitialize()
  366. {
  367.    // keep track of how many times called.  get actual ID to send to on first
  368.    // level, on recursive calls revert to first return.  If need to activate
  369.    // window then do so.  Return FALSE for failure, else non-false is TRUE
  370.    if ( 0 == gKeyPushInitializeDepth++ ) {
  371.       gKPSaveActiveWindow = 0; // assume don't need to change focus
  372.       if ( !gFocusID ) {
  373.          // take whatever is the focus window
  374.          gKPFocusWindow = GetFocus();
  375.       } else if ( !IsWindow(gFocusID) ) {
  376.          gKPFocusWindow = 0;  // gFocusID is not valid
  377.       } else if ( !gFocusIDIsTopLevel ) {
  378.          gKPFocusWindow = gFocusID; // this isn't top level, so is actual window to send to
  379.       } else {
  380.          // this is a top level window, if KeyPushFocusID() set up to make active
  381.          // when sending keystrokes then do so, else send to the child that was
  382.          // the focus when this window was active
  383.          if ( gFocusID == (lActive=GetActiveWindow()) ) {
  384.             gKPFocusWindow = GetFocus();
  385.          } else {
  386.             if ( gKPTempMakeActive ) {
  387.                gKPSaveActiveWindow = lActive;
  388.                SetActiveWindow(gFocusID);
  389.                gKPFocusWindow = GetFocus();
  390.             } else {
  391.                gKPFocusWindow = GetFocusChild(gFocusID);
  392.             }
  393.          }
  394.       }
  395.  
  396.    }
  397.    return gKPFocusWindow;
  398. }
  399.  
  400. KeyPushTerminate()
  401. {
  402.    // undo what KeyPushInitialize did. restore active window if KeyPushInitialize()
  403.    // activated it.  Must call same number of times as KeyPushInitialize.
  404.    if ( 0 == --gKeyPushInitializeDepth ) {
  405.       if ( gKPSaveActiveWindow ) {
  406.          SetActiveWindow(gKPSaveActiveWindow);
  407.       }
  408.    }
  409. }
  410.  
  411. #define HWND_DESKTOP    1
  412. #define ORD_WIN32SETKEYBOARDSTATETABLE   921
  413.  
  414. GetKeyboardTable()   // return 256 byte buffer for current keyboard state
  415. {
  416.    lTable[255] = '\0';   // initialize 256-byte key table
  417.    DynamicLink("PMWIN",ORD_WIN32SETKEYBOARDSTATETABLE,BIT32,CDECL,
  418.                HWND_DESKTOP,lTable,FALSE);
  419.    return(lTable);
  420. }
  421.  
  422. SetKeyboardTable(pKeyBuf)  // set the 256 byte buffer for current keyboard state
  423. {
  424.    DynamicLink("PMWIN",ORD_WIN32SETKEYBOARDSTATETABLE,BIT32,CDECL,
  425.                HWND_DESKTOP,pKeyBuf,TRUE);
  426. }
  427.  
  428.  
  429. /***********************************/
  430. /*** SEND KEY MESSAGES TO WINDOW ***/
  431.  
  432. SendMessageAndAccelTable(pParam1,pParam2)
  433.    // Send this message and send an accelerator table message
  434. {
  435.    // see that the current window has been given access to the shared
  436.    // memory table memory
  437.    lSharedMemory = GiveMemoryToWindow(gKPFocusWindow);
  438.  
  439.    // copy the message to the globally allocated and shared memory
  440.    // build blob message to give to accelerator table
  441.    poke( lSharedMemory, gKPFocusWindow, UWORD32 );
  442.    poke( lSharedMemory+4, WM_CHAR, UWORD32 );
  443.    poke( lSharedMemory+8, pParam1, UWORD32 );
  444.    poke( lSharedMemory+12, pParam2, UWORD32 );
  445.  
  446.    // send message to window accelerator in case it wants to translate
  447.    WinSendMsg(gKPFocusWindow,WM_TRANSLATEACCEL,lSharedMemory,0);
  448.    // send translated message to the window
  449.    WinSendMsg(peek(lSharedMemory,UWORD32),peek(lSharedMemory+4,UWORD32),
  450.               peek(lSharedMemory+8,UWORD32),peek(lSharedMemory+12,UWORD32));
  451. }
  452.