views:

356

answers:

2

I have used sendinput() function and windows keyboard hooks to develop a custom keyboard for indian languages. Project is in google code here: http://code.google.com/p/ekalappai

The keyboad hook and sendinput functions are placed in a win32 dll. And they are called from a Qt exe. Our application works fine for most keys and applications. I find the following issue:

I could not send Backspace key to few applications like Wordpad/Openoffice/MsOffice. I find same issue with Arrowkeys and delete keys.

Here is my code:

extern "C" __declspec(dllexport) void GenerateKey(int vk , bool bExtended)
{
    //update previous characters
    previous_2_character = previous_1_character;
    previous_1_character = vk;

    KEYBDINPUT kb={0};
    INPUT Input={0};

    //keydown
    kb.wVk    =  0;
    kb.wScan = vk;/*enter unicode here*/;
    kb.dwFlags = KEYEVENTF_UNICODE; // KEYEVENTF_UNICODE=4
    Input.type = INPUT_KEYBOARD;
    Input.ki = kb;

    ::SendInput(1,&Input,sizeof(Input));

    //keyup
    kb.wVk    =  0;
    kb.wScan = vk;/*enter unicode here*/;
    kb.dwFlags = KEYEVENTF_UNICODE|KEYEVENTF_KEYUP; //KEYEVENTF_UNICODE=4
    Input.type = INPUT_KEYBOARD;
    Input.ki = kb;

    ::SendInput(1,&Input,sizeof(Input));
}

Full dll code is here: http://code.google.com/p/ekalappai/source/browse/trunk/ekhook/ekhook/dllmain.cpp

Calling code:

generatekey = (GenerateKey) myLib->resolve( "GenerateKey" );

generatekey(44,FALSE); //comma - THis works in wordpad/MsOffice/Openoffice
generatekey(2949,FALSE); //tamil character "a" works in Wordpad/Msoffice/Openoffice

generatekey(8,FALSE); //backspace - This is NOT working in Wordpad/Msoffice/Openoffice

Full calling code from Qt Exe is here: http://code.google.com/p/ekalappai/source/browse/trunk/ekalappai/window.cpp

I tried searching in google but could not fine a solution yet. If anyone has clue on resolving this pls help. Thanks.

+1  A: 

You are mixing up the virtual key and the scan code. The wVk member is the important one, the scan code will only be used it the virtual key is ambiguous. Fix:

kb.wVk   = vk;
kb.wScan = 0;   // TODO: look at VkKeyScanEx()
Hans Passant
No...from the docs: "If the dwFlags member specifies KEYEVENTF_UNICODE, wVk must be 0." http://msdn.microsoft.com/en-us/library/ms646271(VS.85).aspx
Hostile Fork
It worked ! Yes for sending unicode character I retained the existing code(i.e. kb.wVK = 0). For other non character keys like backspace I used kb.wVK = vk; and my problem is solved. Thanks everyone for helping :)
Mugunth
Note the documentation link above: if you're going to set the wVk then you should remove KEYEVENTF_UNICODE. If ignoring that works for *you* on *your system*, it could just be a quirk or a bug. When people implement things like the Wine emulator they go by the documentation, and you don't do them a service by using undocumented behaviors. Also Microsoft might release a patch which brings the routine into compliance and breaks your program.
Hostile Fork
@Hostile: he already figured this out.
Hans Passant
That's not clear from this conversation.
Hostile Fork
A: 

The documentation says:

If KEYEVENTF_UNICODE is specified, SendInput sends a WM_KEYDOWN or WM_KEYUP message to the foreground thread's message queue with wParam equal to VK_PACKET. Once GetMessage or PeekMessage obtains this message, passing the message to TranslateMessage posts a WM_CHAR message with the Unicode character originally specified by wScan.

Just a guess, but the word processing programs might be triggering the backspace behavior off of WM_KEYDOWN/WM_KEYUP messages and not WM_CHAR. Thus they may be expecting VK_BACKSPACE (not VK_PACKET) as the wParam of those messages. It might even be done with accelerators based on VKEYs not characters...heck, you're on Windows, so pretty much anything is possible. :)

Have you tried not using KEYEVENTF_UNICODE, and doing kb.wVk = VK_BACKSPACE ?

(Also, you might use Spy++ to get a better clue of what key messages are sent to the target application and how it differs from when you hit a literal backspace.)

Hostile Fork