Question

I'll try to explain better what I mean, and I'll also try to keep the question free from language, though if there is a way to do what I want in C# without having to reference anything it'd be nice. Anyway.

I am handling keyboard input, and converting it to string. All fine. I get the status for the Shift and CapsLock keys and EXOR it so I can figure out the casing for the resulting string.

bool shift = KeyDown(SHIFT_KEY)
bool capslock = KeyToggled(CAPSLOCK)
bool stringCasing = shift ^ capslock //if both are true/false, the string will be lowercase. Otherwise uppercase.

foreach Key k in [list of keys passed as parameter]
     char c = (char)k
     if stringCasing
          c = Char.ToUpper(c)
     else
          c = Char.ToLower(c)
end foreach

And no problems for now. If a user types "a" while holding shift or having capslock toggled, it becomes a "A".

However, if a user decides to type "!", which is "1" plus shift I only get a 1, because "1" uppercase is still "1".

I looked a bit on the web before asking this question, but all I got was "Map the keys yourself". Is that really the only answer? And also, what would happen if I mapped the keys and then a user with a different keyboard layout tried to use my application? Thanks in advance.

Was it helpful?

Solution

This can be accomplished through the Win32 ToAscii function (MSDN reference). I don't know of any .NET framework methods that wrap these functions, so it may be necessary to use P/Invoke.

Along with ToAscii, you may need a reference to VkKeyScan to translate the key into a virtual key code. This key code is used as a parameter to ToAscii. Simple P/Invoke declarations for these methods follow:

    [DllImport("user32.dll")]
    static extern short VkKeyScan(char c);

    [DllImport("user32.dll", SetLastError=true)]
    static extern int ToAscii(
        uint uVirtKey,
        uint uScanCode,
        byte[] lpKeyState,
        out uint lpChar,
        uint flags
        );

Note the the third parameter to ToAscii is a 256-element array that references the state of each key; a value of 0x80 (high bit set) indicates the key is set. Setting element 0x10 (the virtual key code for Shift) emulates Shift being pressed.

We can then define a helper method that takes as a parameter a character representing a key, and outputs that key with Shift depressed:

public static char GetModifiedKey(char c)
{
    short vkKeyScanResult = VkKeyScan(c);

    // a result of -1 indicates no key translates to input character
    if (vkKeyScanResult == -1)
        throw new ArgumentException("No key mapping for " + c);

    // vkKeyScanResult & 0xff is the base key, without any modifiers
    uint code = (uint)vkKeyScanResult & 0xff;

    // set shift key pressed
    byte[] b = new byte[256];
    b[0x10] = 0x80;

    uint r;
    // return value of 1 expected (1 character copied to r)
    if (1 != ToAscii(code, code, b, out r, 0))
        throw new ApplicationException("Could not translate modified state");

    return (char)r;
}

Calling this method will return the character associated with Shift+base key for the input character (where the base key is the physical key pressed to enter the character, e.g., 1 is the base key for !). For instance, for a US keyboard, GetModifiedKey('7') and GetModifiedKey('&') will both return '&'. The return value will use the loaded keyboard layout; for example, on a German keyboard (where Shift+7 is /), the method will return / instead.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top