VirtualBox

Changeset 64906 in vbox


Ignore:
Timestamp:
Dec 16, 2016 1:01:20 PM (8 years ago)
Author:
vboxsync
Message:

VBoxManage: limit keyboardputscancode 'typing' rate. Simple commands to 'type' ASCII chars.

Location:
trunk/src/VBox/Frontends/VBoxManage
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Frontends/VBoxManage/VBoxManageControlVM.cpp

    r63567 r64906  
    8181}
    8282
     83#define KBDCHARDEF_MOD_NONE  0x00
     84#define KBDCHARDEF_MOD_SHIFT 0x01
     85
     86typedef struct KBDCHARDEF
     87{
     88    uint8_t u8Scancode;
     89    uint8_t u8Modifiers;
     90} KBDCHARDEF;
     91
     92static const KBDCHARDEF g_aASCIIChars[0x80] =
     93{
     94    /* 0x00 ' ' */ {0x00, KBDCHARDEF_MOD_NONE},
     95    /* 0x01 ' ' */ {0x00, KBDCHARDEF_MOD_NONE},
     96    /* 0x02 ' ' */ {0x00, KBDCHARDEF_MOD_NONE},
     97    /* 0x03 ' ' */ {0x00, KBDCHARDEF_MOD_NONE},
     98    /* 0x04 ' ' */ {0x00, KBDCHARDEF_MOD_NONE},
     99    /* 0x05 ' ' */ {0x00, KBDCHARDEF_MOD_NONE},
     100    /* 0x06 ' ' */ {0x00, KBDCHARDEF_MOD_NONE},
     101    /* 0x07 ' ' */ {0x00, KBDCHARDEF_MOD_NONE},
     102    /* 0x08 ' ' */ {0x00, KBDCHARDEF_MOD_NONE},
     103    /* 0x09 ' ' */ {0x00, KBDCHARDEF_MOD_NONE},
     104    /* 0x0A ' ' */ {0x1c, KBDCHARDEF_MOD_NONE},
     105    /* 0x0B ' ' */ {0x00, KBDCHARDEF_MOD_NONE},
     106    /* 0x0C ' ' */ {0x00, KBDCHARDEF_MOD_NONE},
     107    /* 0x0D ' ' */ {0x00, KBDCHARDEF_MOD_NONE},
     108    /* 0x0E ' ' */ {0x00, KBDCHARDEF_MOD_NONE},
     109    /* 0x0F ' ' */ {0x00, KBDCHARDEF_MOD_NONE},
     110    /* 0x10 ' ' */ {0x00, KBDCHARDEF_MOD_NONE},
     111    /* 0x11 ' ' */ {0x00, KBDCHARDEF_MOD_NONE},
     112    /* 0x12 ' ' */ {0x00, KBDCHARDEF_MOD_NONE},
     113    /* 0x13 ' ' */ {0x00, KBDCHARDEF_MOD_NONE},
     114    /* 0x14 ' ' */ {0x00, KBDCHARDEF_MOD_NONE},
     115    /* 0x15 ' ' */ {0x00, KBDCHARDEF_MOD_NONE},
     116    /* 0x16 ' ' */ {0x00, KBDCHARDEF_MOD_NONE},
     117    /* 0x17 ' ' */ {0x00, KBDCHARDEF_MOD_NONE},
     118    /* 0x18 ' ' */ {0x00, KBDCHARDEF_MOD_NONE},
     119    /* 0x19 ' ' */ {0x00, KBDCHARDEF_MOD_NONE},
     120    /* 0x1A ' ' */ {0x00, KBDCHARDEF_MOD_NONE},
     121    /* 0x1B ' ' */ {0x00, KBDCHARDEF_MOD_NONE},
     122    /* 0x1C ' ' */ {0x00, KBDCHARDEF_MOD_NONE},
     123    /* 0x1D ' ' */ {0x00, KBDCHARDEF_MOD_NONE},
     124    /* 0x1E ' ' */ {0x00, KBDCHARDEF_MOD_NONE},
     125    /* 0x1F ' ' */ {0x00, KBDCHARDEF_MOD_NONE},
     126    /* 0x20 ' ' */ {0x39, KBDCHARDEF_MOD_NONE},
     127    /* 0x21 '!' */ {0x02, KBDCHARDEF_MOD_NONE},
     128    /* 0x22 '"' */ {0x28, KBDCHARDEF_MOD_SHIFT},
     129    /* 0x23 '#' */ {0x04, KBDCHARDEF_MOD_SHIFT},
     130    /* 0x24 '$' */ {0x05, KBDCHARDEF_MOD_SHIFT},
     131    /* 0x25 '%' */ {0x06, KBDCHARDEF_MOD_SHIFT},
     132    /* 0x26 '&' */ {0x08, KBDCHARDEF_MOD_SHIFT},
     133    /* 0x27 ''' */ {0x28, KBDCHARDEF_MOD_NONE},
     134    /* 0x28 '(' */ {0x0a, KBDCHARDEF_MOD_SHIFT},
     135    /* 0x29 ')' */ {0x0b, KBDCHARDEF_MOD_SHIFT},
     136    /* 0x2A '*' */ {0x09, KBDCHARDEF_MOD_SHIFT},
     137    /* 0x2B '+' */ {0x0d, KBDCHARDEF_MOD_SHIFT},
     138    /* 0x2C ',' */ {0x33, KBDCHARDEF_MOD_NONE},
     139    /* 0x2D '-' */ {0x0c, KBDCHARDEF_MOD_NONE},
     140    /* 0x2E '.' */ {0x34, KBDCHARDEF_MOD_NONE},
     141    /* 0x2F '/' */ {0x35, KBDCHARDEF_MOD_NONE},
     142    /* 0x30 '0' */ {0x0b, KBDCHARDEF_MOD_NONE},
     143    /* 0x31 '1' */ {0x02, KBDCHARDEF_MOD_NONE},
     144    /* 0x32 '2' */ {0x03, KBDCHARDEF_MOD_NONE},
     145    /* 0x33 '3' */ {0x04, KBDCHARDEF_MOD_NONE},
     146    /* 0x34 '4' */ {0x05, KBDCHARDEF_MOD_NONE},
     147    /* 0x35 '5' */ {0x06, KBDCHARDEF_MOD_NONE},
     148    /* 0x36 '6' */ {0x07, KBDCHARDEF_MOD_NONE},
     149    /* 0x37 '7' */ {0x08, KBDCHARDEF_MOD_NONE},
     150    /* 0x38 '8' */ {0x09, KBDCHARDEF_MOD_NONE},
     151    /* 0x39 '9' */ {0x0a, KBDCHARDEF_MOD_NONE},
     152    /* 0x3A ':' */ {0x27, KBDCHARDEF_MOD_SHIFT},
     153    /* 0x3B ';' */ {0x27, KBDCHARDEF_MOD_NONE},
     154    /* 0x3C '<' */ {0x33, KBDCHARDEF_MOD_SHIFT},
     155    /* 0x3D '=' */ {0x0d, KBDCHARDEF_MOD_NONE},
     156    /* 0x3E '>' */ {0x34, KBDCHARDEF_MOD_SHIFT},
     157    /* 0x3F '?' */ {0x35, KBDCHARDEF_MOD_SHIFT},
     158    /* 0x40 '@' */ {0x03, KBDCHARDEF_MOD_SHIFT},
     159    /* 0x41 'A' */ {0x1e, KBDCHARDEF_MOD_SHIFT},
     160    /* 0x42 'B' */ {0x30, KBDCHARDEF_MOD_SHIFT},
     161    /* 0x43 'C' */ {0x2e, KBDCHARDEF_MOD_SHIFT},
     162    /* 0x44 'D' */ {0x20, KBDCHARDEF_MOD_SHIFT},
     163    /* 0x45 'E' */ {0x12, KBDCHARDEF_MOD_SHIFT},
     164    /* 0x46 'F' */ {0x21, KBDCHARDEF_MOD_SHIFT},
     165    /* 0x47 'G' */ {0x22, KBDCHARDEF_MOD_SHIFT},
     166    /* 0x48 'H' */ {0x23, KBDCHARDEF_MOD_SHIFT},
     167    /* 0x49 'I' */ {0x17, KBDCHARDEF_MOD_SHIFT},
     168    /* 0x4A 'J' */ {0x24, KBDCHARDEF_MOD_SHIFT},
     169    /* 0x4B 'K' */ {0x25, KBDCHARDEF_MOD_SHIFT},
     170    /* 0x4C 'L' */ {0x26, KBDCHARDEF_MOD_SHIFT},
     171    /* 0x4D 'M' */ {0x32, KBDCHARDEF_MOD_SHIFT},
     172    /* 0x4E 'N' */ {0x31, KBDCHARDEF_MOD_SHIFT},
     173    /* 0x4F 'O' */ {0x18, KBDCHARDEF_MOD_SHIFT},
     174    /* 0x50 'P' */ {0x19, KBDCHARDEF_MOD_SHIFT},
     175    /* 0x51 'Q' */ {0x10, KBDCHARDEF_MOD_SHIFT},
     176    /* 0x52 'R' */ {0x13, KBDCHARDEF_MOD_SHIFT},
     177    /* 0x53 'S' */ {0x1f, KBDCHARDEF_MOD_SHIFT},
     178    /* 0x54 'T' */ {0x14, KBDCHARDEF_MOD_SHIFT},
     179    /* 0x55 'U' */ {0x16, KBDCHARDEF_MOD_SHIFT},
     180    /* 0x56 'V' */ {0x2f, KBDCHARDEF_MOD_SHIFT},
     181    /* 0x57 'W' */ {0x11, KBDCHARDEF_MOD_SHIFT},
     182    /* 0x58 'X' */ {0x2d, KBDCHARDEF_MOD_SHIFT},
     183    /* 0x59 'Y' */ {0x15, KBDCHARDEF_MOD_SHIFT},
     184    /* 0x5A 'Z' */ {0x2c, KBDCHARDEF_MOD_SHIFT},
     185    /* 0x5B '[' */ {0x1a, KBDCHARDEF_MOD_NONE},
     186    /* 0x5C '\' */ {0x2b, KBDCHARDEF_MOD_NONE},
     187    /* 0x5D ']' */ {0x1b, KBDCHARDEF_MOD_NONE},
     188    /* 0x5E '^' */ {0x07, KBDCHARDEF_MOD_SHIFT},
     189    /* 0x5F '_' */ {0x0c, KBDCHARDEF_MOD_SHIFT},
     190    /* 0x60 '`' */ {0x28, KBDCHARDEF_MOD_NONE},
     191    /* 0x61 'a' */ {0x1e, KBDCHARDEF_MOD_NONE},
     192    /* 0x62 'b' */ {0x30, KBDCHARDEF_MOD_NONE},
     193    /* 0x63 'c' */ {0x2e, KBDCHARDEF_MOD_NONE},
     194    /* 0x64 'd' */ {0x20, KBDCHARDEF_MOD_NONE},
     195    /* 0x65 'e' */ {0x12, KBDCHARDEF_MOD_NONE},
     196    /* 0x66 'f' */ {0x21, KBDCHARDEF_MOD_NONE},
     197    /* 0x67 'g' */ {0x22, KBDCHARDEF_MOD_NONE},
     198    /* 0x68 'h' */ {0x23, KBDCHARDEF_MOD_NONE},
     199    /* 0x69 'i' */ {0x17, KBDCHARDEF_MOD_NONE},
     200    /* 0x6A 'j' */ {0x24, KBDCHARDEF_MOD_NONE},
     201    /* 0x6B 'k' */ {0x25, KBDCHARDEF_MOD_NONE},
     202    /* 0x6C 'l' */ {0x26, KBDCHARDEF_MOD_NONE},
     203    /* 0x6D 'm' */ {0x32, KBDCHARDEF_MOD_NONE},
     204    /* 0x6E 'n' */ {0x31, KBDCHARDEF_MOD_NONE},
     205    /* 0x6F 'o' */ {0x18, KBDCHARDEF_MOD_NONE},
     206    /* 0x70 'p' */ {0x19, KBDCHARDEF_MOD_NONE},
     207    /* 0x71 'q' */ {0x10, KBDCHARDEF_MOD_NONE},
     208    /* 0x72 'r' */ {0x13, KBDCHARDEF_MOD_NONE},
     209    /* 0x73 's' */ {0x1f, KBDCHARDEF_MOD_NONE},
     210    /* 0x74 't' */ {0x14, KBDCHARDEF_MOD_NONE},
     211    /* 0x75 'u' */ {0x16, KBDCHARDEF_MOD_NONE},
     212    /* 0x76 'v' */ {0x2f, KBDCHARDEF_MOD_NONE},
     213    /* 0x77 'w' */ {0x11, KBDCHARDEF_MOD_NONE},
     214    /* 0x78 'x' */ {0x2d, KBDCHARDEF_MOD_NONE},
     215    /* 0x79 'y' */ {0x15, KBDCHARDEF_MOD_NONE},
     216    /* 0x7A 'z' */ {0x2c, KBDCHARDEF_MOD_NONE},
     217    /* 0x7B '{' */ {0x1a, KBDCHARDEF_MOD_SHIFT},
     218    /* 0x7C '|' */ {0x2b, KBDCHARDEF_MOD_SHIFT},
     219    /* 0x7D '}' */ {0x1b, KBDCHARDEF_MOD_SHIFT},
     220    /* 0x7E '~' */ {0x29, KBDCHARDEF_MOD_SHIFT},
     221    /* 0x7F ' ' */ {0x00, KBDCHARDEF_MOD_NONE},
     222};
     223
     224static HRESULT keyboardPutScancodes(IKeyboard *pKeyboard, const std::list<LONG> &llScancodes)
     225{
     226    /* Send scancodes to the VM. */
     227    com::SafeArray<LONG> saScancodes(llScancodes);
     228
     229#if 1
     230    HRESULT rc = S_OK;
     231    int i;
     232    for (i = 0; i < saScancodes.size(); ++i)
     233    {
     234        rc = pKeyboard->PutScancode(saScancodes[i]);
     235        if (FAILED(rc))
     236        {
     237            RTMsgError("Failed to send a scancode");
     238            break;
     239        }
     240
     241        RTThreadSleep(10); /* "Typing" too fast causes lost characters. */
     242    }
     243#else
     244    /** @todo PutScancodes does not deliver more than 20 scancodes. */
     245    ULONG codesStored = 0;
     246    HRESULT rc = pKeyboard->PutScancodes(ComSafeArrayAsInParam(saScancodes),
     247                                         &codesStored);
     248    if (SUCCEEDED(rc) && codesStored < saScancodes.size())
     249    {
     250        RTMsgError("Only %d scancodes were stored", codesStored);
     251        rc = E_FAIL;
     252    }
     253#endif
     254
     255    return rc;
     256}
     257
     258static void keyboardCharsToScancodes(const char *pch, size_t cchMax, std::list<LONG> &llScancodes, bool *pfShift)
     259{
     260    size_t cchProcessed = 0;
     261    const char *p = pch;
     262    while (cchProcessed < cchMax)
     263    {
     264        ++cchProcessed;
     265        const uint8_t c = (uint8_t)*p++;
     266        if (c < RT_ELEMENTS(g_aASCIIChars))
     267        {
     268            const KBDCHARDEF *d = &g_aASCIIChars[c];
     269            if (d->u8Scancode)
     270            {
     271                const bool fNeedShift = RT_BOOL(d->u8Modifiers & KBDCHARDEF_MOD_SHIFT);
     272                if (*pfShift != fNeedShift)
     273                {
     274                    *pfShift = fNeedShift;
     275                    /* Press or release the SHIFT key. */
     276                    llScancodes.push_back(0x2a | (fNeedShift? 0x00: 0x80));
     277                }
     278
     279                llScancodes.push_back(d->u8Scancode);
     280                llScancodes.push_back(d->u8Scancode | 0x80);
     281            }
     282        }
     283    }
     284}
     285
     286static HRESULT keyboardPutString(IKeyboard *pKeyboard, int argc, char **argv)
     287{
     288    std::list<LONG> llScancodes;
     289    bool fShift = false;
     290
     291    /* Convert command line string(s) to the en-us keyboard scancodes. */
     292    int i;
     293    for (i = 1 + 1; i < argc; ++i)
     294    {
     295        if (llScancodes.size() > 0)
     296        {
     297            /* Insert a SPACE before the next string. */
     298            llScancodes.push_back(0x39);
     299            llScancodes.push_back(0x39 | 0x80);
     300        }
     301
     302        keyboardCharsToScancodes(argv[i], strlen(argv[i]), llScancodes, &fShift);
     303    }
     304
     305    /* Release SHIFT if pressed. */
     306    if (fShift)
     307        llScancodes.push_back(0x2a | 0x80);
     308
     309    return keyboardPutScancodes(pKeyboard, llScancodes);
     310}
     311
     312static HRESULT keyboardPutFile(IKeyboard *pKeyboard, const char *pszFilename)
     313{
     314    std::list<LONG> llScancodes;
     315    bool fShift = false;
     316
     317    RTFILE File = NIL_RTFILE;
     318    int vrc = RTFileOpen(&File, pszFilename, RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE);
     319    if (RT_SUCCESS(vrc))
     320    {
     321        uint64_t cbFile = 0;
     322        vrc = RTFileGetSize(File, &cbFile);
     323        if (RT_SUCCESS(vrc))
     324        {
     325            const uint64_t cbFileMax = _64K;
     326            if (cbFile <= cbFileMax)
     327            {
     328                const size_t cbBuffer = _4K;
     329                char *pchBuf = (char *)RTMemAlloc(cbBuffer);
     330                if (pchBuf)
     331                {
     332                    size_t cbRemaining = (size_t)cbFile;
     333                    while (cbRemaining > 0)
     334                    {
     335                        const size_t cbToRead = cbRemaining > cbBuffer ? cbBuffer : cbRemaining;
     336
     337                        size_t cbRead = 0;
     338                        vrc = RTFileRead(File, pchBuf, cbToRead, &cbRead);
     339                        if (RT_FAILURE(vrc) || cbRead == 0)
     340                            break;
     341
     342                        keyboardCharsToScancodes(pchBuf, cbRead, llScancodes, &fShift);
     343                        cbRemaining -= cbRead;
     344                    }
     345
     346                    RTMemFree(pchBuf);
     347                }
     348                else
     349                    RTMsgError("Out of memory allocating %d bytes", cbBuffer);
     350            }
     351            else
     352                RTMsgError("File size %RI64 is greater than %RI64: '%s'", cbFile, cbFileMax, pszFilename);
     353        }
     354        else
     355            RTMsgError("Cannot get size of file '%s': %Rrc", pszFilename, vrc);
     356
     357        RTFileClose(File);
     358    }
     359    else
     360        RTMsgError("Cannot open file '%s': %Rrc", pszFilename, vrc);
     361
     362    /* Release SHIFT if pressed. */
     363    if (fShift)
     364        llScancodes.push_back(0x2a | 0x80);
     365
     366    return keyboardPutScancodes(pKeyboard, llScancodes);
     367}
     368
    83369
    84370RTEXITCODE handleControlVM(HandlerArg *a)
     
    339625                break;
    340626
    341             /* Send scancodes to the VM. */
    342             com::SafeArray<LONG> saScancodes(llScancodes);
    343             ULONG codesStored = 0;
    344             CHECK_ERROR_BREAK(pKeyboard, PutScancodes(ComSafeArrayAsInParam(saScancodes),
    345                                                      &codesStored));
    346             if (codesStored < saScancodes.size())
    347             {
    348                 RTMsgError("Only %d scancodes were stored", codesStored);
    349                 rc = E_FAIL;
    350                 break;
    351             }
     627            rc = keyboardPutScancodes(pKeyboard, llScancodes);
     628        }
     629        else if (!strcmp(a->argv[1], "keyboardputstring"))
     630        {
     631            ComPtr<IKeyboard> pKeyboard;
     632            CHECK_ERROR_BREAK(console, COMGETTER(Keyboard)(pKeyboard.asOutParam()));
     633            if (!pKeyboard)
     634            {
     635                RTMsgError("Guest not running");
     636                rc = E_FAIL;
     637                break;
     638            }
     639
     640            if (a->argc <= 1 + 1)
     641            {
     642                errorArgument("Missing argument to '%s'. Expected ASCII string(s).", a->argv[1]);
     643                rc = E_FAIL;
     644                break;
     645            }
     646
     647            rc = keyboardPutString(pKeyboard, a->argc, a->argv);
     648        }
     649        else if (!strcmp(a->argv[1], "keyboardputfile"))
     650        {
     651            ComPtr<IKeyboard> pKeyboard;
     652            CHECK_ERROR_BREAK(console, COMGETTER(Keyboard)(pKeyboard.asOutParam()));
     653            if (!pKeyboard)
     654            {
     655                RTMsgError("Guest not running");
     656                rc = E_FAIL;
     657                break;
     658            }
     659
     660            if (a->argc <= 1 + 1)
     661            {
     662                errorArgument("Missing argument to '%s'. Expected file name.", a->argv[1]);
     663                rc = E_FAIL;
     664                break;
     665            }
     666
     667            rc = keyboardPutFile(pKeyboard, a->argv[2]);
    352668        }
    353669        else if (!strncmp(a->argv[1], "setlinkstate", 12))
  • trunk/src/VBox/Frontends/VBoxManage/VBoxManageHelp.cpp

    r64434 r64906  
    961961                     "                            acpipowerbutton|acpisleepbutton|\n"
    962962                     "                            keyboardputscancode <hex> [<hex> ...]|\n"
     963                     "                            keyboardputstring <string1> [<string2> ...]|\n"
     964                     "                            keyboardputfile <filename>|\n"
    963965                     "                            setlinkstate<1-N> on|off |\n"
    964966#if defined(VBOX_WITH_NETFLT)
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette