I'm working on a project at work and I'm a bit stumped. We have a graphical display which processes keyboard input and zooms in on a display when either the + on the numpad or the + above the equals key are pressed. It works nicely on most computers, but on a Swiss (German) layout, the + key is instead Shift+1. We are currently using OnKeyDown, which returns the key value which is pressed (The '1' key value of 49 if I'm trying to handle the Swiss +) as well as boolean variables indicating whether the shift, control, and alt keys are pressed. I've looked at using OnKeyPress, but I seem to lose the ability to check whether the Control key is pressed there.

I may have a potential solution at how to capture the '#' character on different locale keyboards in WPF/C#?, but pulling in external DLLs to properly localize a keyboard to use the + key the same no matter what language the keyboard is set to seems dreadfully inelegant. I'd like to believe that, since 2012, Microsoft has added something native to the C# language to process keyboard input in foreign layouts without jumping through hoops.

Worse comes to worse, I can always detect which keyboard layout is being used and handle this as a special case, but that seems to be a last-resort kind of thing.

The code at Keyboard Mapping in .NET is slightly more useful, but it's got some brittle bits to it, like accessing an array outside of its boundaries if it gets Keys.Shift instead of Keys.ShiftKey, and it still requires pulling in the outside DLL. Is this really something that Microsoft find unimportant?

Edit: I think that I have it working with the code from above about "Keyboard Mapping in .NET". I'm getting the correct values for all of the keys accessed by pressing shift and a key. I'm a bit worried that I'm going to miss some other case involving adding Control or Alt to it, but it functions. I would still prefer a more elegant solution.

Further Edit: The technique at Get the char on Control.KeyDown? also works for a given control.

Later Edit: Right. It functions as it ought to, but it looks like my error was always something simpler. The non-numpad "plus" should always map to Keys.Oemplus for the KeyCode in the event no matter what button press triggers it. It doesn't for the Swiss keyboard and possibly others that I've yet to find. Interesting. I have no idea where I would even report that.

有帮助吗?

解决方案

Ultimately, I went with the code at How to convert a virtual-key code to a character according to the current keyboard layout?. I still think that this should be easier to build into the code, but it should suffice for now.

  [DllImport("user32.dll")]
  public static extern int ToUnicode(
      uint wVirtKey,
      uint wScanCode,
      byte[] lpKeyState,
      [Out, MarshalAs(UnmanagedType.LPWStr, SizeParamIndex = 4)] 
        StringBuilder pwszBuff,
      int cchBuff,
      uint wFlags);

  static string GetCharsFromKeys(Keys keys, bool shift, bool altGr)
  {
     var buf = new StringBuilder(256);
     var keyboardState = new byte[256];
     if (shift)
        keyboardState[(int)Keys.ShiftKey] = 0xff;
     if (altGr)
     {
        keyboardState[(int)Keys.ControlKey] = 0xff;
        keyboardState[(int)Keys.Menu] = 0xff;
     }
     ToUnicode((uint)keys, 0, keyboardState, buf, 256, 0);
     return buf.ToString();
  }
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top