using System; using System.Collections.Generic; using System.Linq; using System.Runtime.InteropServices; using System.Text; using System.Threading.Tasks; using SharpDX.DirectInput; namespace SCJMapper_V2.Common { static class WinApi { public const string LibraryName = "user32"; internal static class Properties { #if !ANSI public const CharSet BuildCharSet = CharSet.Unicode; #else public const CharSet BuildCharSet = CharSet.Ansi; #endif } /// /// The set of valid MapTypes used in MapVirtualKey /// public enum VirtualKeyMapType { /// /// The uCode parameter is a virtual-key code and is translated into a scan code. /// If it is a virtual-key code that does not distinguish between left- and right-hand keys, /// the left-hand scan code is returned. /// If there is no translation, the function returns 0. /// MAPVK_VK_TO_VSC = 0x0, /// /// The uCode parameter is a scan code and is translated into a virtual-key code that does /// not distinguish between left- and right-hand keys. /// If there is no translation, the function returns 0. /// MAPVK_VSC_TO_VK = 0x1, /// /// The uCode parameter is a virtual-key code and is translated into an unshifted character /// value in the low order word of the return value. Dead keys (diacritics) are indicated /// by setting the top bit of the return value. /// If there is no translation, the function returns 0. /// MAPVK_VK_TO_CHAR = 0x2, /// /// The uCode parameter is a scan code and is translated into a virtual-key code that /// distinguishes between left- and right-hand keys. /// If there is no translation, the function returns 0. /// MAPVK_VSC_TO_VK_EX = 0x3, /// /// The uCode parameter is a virtual-key code and is translated into a scan code. /// If it is a virtual-key code that does not distinguish between left- and right-hand keys, /// the left-hand scan code is returned. If the scan code is an extended scan code, /// the high byte of the uCode value can contain either 0xe0 or 0xe1 to specify the extended scan code. /// If there is no translation, the function returns 0. /// MAPVK_VK_TO_VSC_EX = 0x4, } /// /// Translates (maps) a virtual-key code into a scan code or character value, /// or translates a scan code into a virtual-key code. /// The function translates the codes using the input language and an input locale identifier. /// /// NOTE: DX Keycodes are VSC codes (Scan Codes) /// /// Scan code for a key. /// Starting with Windows Vista, the high byte of the uCode value can contain /// either 0xe0 or 0xe1 to specify the extended scan code. /// /// MAPVK_VSC_TO_VK, MAPVK_VSC_TO_VK_EX /// nput locale identifier to use for translating the specified code. /// Either a scan code, a virtual-key code, or a character value, /// depending on the value of uCode and uMapType. /// If there is no translation, the return value is zero. /// [DllImport( LibraryName, CharSet = Properties.BuildCharSet )] public static extern uint MapVirtualKeyEx( uint uCode, VirtualKeyMapType uMapType, IntPtr dwhkl ); /// /// Translates (maps) a virtual-key code into a scan code or character value, /// or translates a scan code into a virtual-key code. /// The function translates the codes using the input language and an input locale identifier. /// /// NOTE: DX Keycodes are VSC codes /// /// The virtual-key code for a key. /// Starting with Windows Vista, the high byte of the uCode value can contain /// either 0xe0 or 0xe1 to specify the extended scan code. /// /// MAPVK_VK_TO_VSC, MAPVK_VK_TO_CHAR, MAPVK_VK_TO_VSC_EX /// nput locale identifier to use for translating the specified code. /// Either a scan code, a virtual-key code, or a character value, /// depending on the value of uCode and uMapType. /// If there is no translation, the return value is zero. /// [DllImport( LibraryName, CharSet = Properties.BuildCharSet )] public static extern uint MapVirtualKeyEx( VirtualKey uCode, VirtualKeyMapType uMapType, IntPtr dwhkl ); /// /// The above does not work great - cannot get Navigation buttons, returns Numpad as Navig. e.g. NumLock OFF (seems to be stuck with the OLD DOS PC Keyboard layout...) /// We only need the Alpha Keyboard to be translated by the MS routine.. /// /// The ScanCode /// /// /// public static string KbdScanCodeToVK( uint uCode ) { switch ( uCode ) { // handle modifiers first case (uint)Key.LeftAlt: return "LAlt"; case (uint)Key.RightAlt: return "RAlt"; case (uint)Key.LeftShift: return "LShift"; case (uint)Key.RightShift: return "RShift"; case (uint)Key.LeftControl: return "LCtrl"; case (uint)Key.RightControl: return "RCtrl"; // all keys where the DX name does not match the SC name // Numpad case (uint)Key.NumberLock: return "N.Lck"; case (uint)Key.Divide: return "NP /"; case (uint)Key.Multiply: return "NP *"; case (uint)Key.Subtract: return "NP -"; case (uint)Key.Add: return "NP +"; case (uint)Key.Decimal: return "NP ."; case (uint)Key.NumberPadEnter: return "NP ←┘"; case (uint)Key.NumberPad0: return "NP 0"; case (uint)Key.NumberPad1: return "NP 1"; case (uint)Key.NumberPad2: return "NP 2"; case (uint)Key.NumberPad3: return "NP 3"; case (uint)Key.NumberPad4: return "NP 4"; case (uint)Key.NumberPad5: return "NP 5"; case (uint)Key.NumberPad6: return "NP 6"; case (uint)Key.NumberPad7: return "NP 7"; case (uint)Key.NumberPad8: return "NP 8"; case (uint)Key.NumberPad9: return "NP 9"; // Digits case (uint)Key.D0: return "0"; case (uint)Key.D1: return "1"; case (uint)Key.D2: return "2"; case (uint)Key.D3: return "3"; case (uint)Key.D4: return "4"; case (uint)Key.D5: return "5"; case (uint)Key.D6: return "6"; case (uint)Key.D7: return "7"; case (uint)Key.D8: return "8"; case (uint)Key.D9: return "9"; // navigation case (uint)Key.Insert: return "Ins"; case (uint)Key.Home: return "⸠◄9"; case (uint)Key.Delete: return "Del"; case (uint)Key.End: return "►⸡"; case (uint)Key.PageUp: return "Pg▲"; case (uint)Key.PageDown: return "Pg▼"; case (uint)Key.PrintScreen: return "PrtScr"; case (uint)Key.ScrollLock: return "ScrlLck"; case (uint)Key.Pause: return "Pause"; // Arrows case (uint)Key.Up: return "↑"; case (uint)Key.Down: return "↓"; case (uint)Key.Left: return "←"; case (uint)Key.Right: return "→"; // non letters case (uint)Key.Period: return "."; case (uint)Key.Minus: return "-"; case (uint)Key.Equals: return "="; case (uint)Key.Return: return "←┘"; /* case (uint)Key.Grave: return "^"; case (uint)Key.Escape: return "→"; case (uint)Key.Underline: key += "underline+"; break; case (uint)Key.Back: key += "backspace+"; break; case (uint)Key.Tab: key += "tab+"; break; case (uint)Key.LeftBracket: key += "lbracket+"; break; case (uint)Key.RightBracket: key += "rbracket+"; break; case (uint)Key.Capital: key += "capslock+"; break; case (uint)Key.Colon: key += "colon+"; break; case (uint)Key.Backslash: key += "backslash+"; break; case (uint)Key.Comma: key += "comma+"; break; case (uint)Key.Slash: key += "slash+"; break; case (uint)Key.Space: key += "space+"; break; case (uint)Key.Semicolon: key += "semicolon+"; break; case (uint)Key.Apostrophe: key += "apostrophe+"; break; */ // all where the lowercase DX name matches the SC name default: uint vKeyCode = MapVirtualKeyEx( uCode, VirtualKeyMapType.MAPVK_VSC_TO_VK_EX, IntPtr.Zero ); string key = ( (System.Windows.Forms.Keys)vKeyCode ).ToString( ); if ( key.StartsWith( "Oem" ) ) { key = GetCharFromKey( vKeyCode ); // try this ... } return key; } } [DllImport( LibraryName, ExactSpelling = true )] public static extern uint ToAscii( uint uVirtKey, uint uScanCode, [MarshalAs( UnmanagedType.LPArray, SizeConst = 256 )] byte[] lpbKeyState, out uint lpwTransKey, uint uFlags ); [DllImport( LibraryName, ExactSpelling = true )] public static extern uint ToUnicode( uint wVirtKey, uint wScanCode, [MarshalAs( UnmanagedType.LPArray, SizeConst = 256 )] byte[] lpbKeyState, out uint pwszBuff, int cchBuff, uint uFlags ); [DllImport( LibraryName, ExactSpelling = true )] public static extern bool GetKeyboardState( [MarshalAs( UnmanagedType.LPArray, SizeConst = 256 )] out byte[] lpKeyState ); [DllImport( LibraryName, ExactSpelling = true )] [return: MarshalAs( UnmanagedType.Bool )] static extern bool GetKeyboardState( byte[] lpKeyState ); [DllImport( LibraryName, ExactSpelling = true )] public static extern bool GetKeyboardState( IntPtr lpKeyState ); public static string GetCharFromKey( uint virtKeyCode ) { byte[] keyBoardState = new byte[256]; if ( GetKeyboardState( keyBoardState ) ) { if ( ToAscii( virtKeyCode, 0, keyBoardState, out uint outChar, 0 ) < 0 ) { // dead key i.e. not a pressed one if ( outChar <= 255 ) { return ( (char)outChar ).ToString( ); } else { //return Microsoft.VisualBasic.Left(StrConv(ChrW(Out), vbUnicode), 1) //return Microsoft.VisualBasic.Left(StrConv(ChrW(Out), VbStrConv.None), 1) return ( (char)outChar ).ToString( ); } } else { return ( (char)outChar ).ToString( ); } } else { return ""; } } } }