C#에 DataGrid를 다루다 보면 cell BeginEdit(셀 에디트를 위해)를 호출 하게 되는데 , 이때 영어 같은 경우는 합성 문자가 아니기 때문에 상관이 없지만, 한글 같은 경우는 합성 문자이기때문에 첫번째 타이핑을 할때 IME_Composition 인 상태의 커서를 만들어야 한글 입력이 제대로 된다.
하지만 DataGrid(WPF)의 경우에는 딱히 지원이 없어 보인다. 또 나같은 경우는 한글키 입력 일경우에는 KEY_DOWN 메세지 자체를 프로그램에서 캐치 하지 못했다. 해서 전역 후킹을 통해서 이문제를 해결했다.
@소스코드
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 | #region 전역 후킹 const int VK_PROCESSKEY = 0xE5; const int WM_IME_COMPOSITION = 0x10F; const int WM_IME_ENDCOMPOSITION = 0x10E; const int KEYEVENTF_EXTENDEDKEY = 0x1; const int KEYEVENTF_KEYUP = 0x2; [DllImport( "user32.dll" )] static extern bool keybd_event( byte bVk, byte bScan, uint dwFlags, int dwExtraInfo); [DllImport( "user32.dll" )] static extern IntPtr SetWindowsHookEx( int idHook, LowLevelKeyboardProc callback, IntPtr hInstance, uint threadId); [DllImport( "user32.dll" )] static extern bool UnhookWindowsHookEx(IntPtr hInstance); [DllImport( "user32.dll" )] static extern IntPtr CallNextHookEx(IntPtr idHook, int nCode, int wParam, IntPtr lParam); [DllImport( "kernel32.dll" )] static extern IntPtr LoadLibrary( string lpFileName); private delegate IntPtr LowLevelKeyboardProc( int nCode, IntPtr wParam, IntPtr lParam); const int WH_KEYBOARD_LL = 13; // Номер глобального LowLevel-хука на клавиатуру const int WM_KEYDOWN = 0x100; // Сообщения нажатия клавиши const int WM_IME_STARTCOMPOSITION = 0x010D; #region VirtualKey public enum VKeys : int { VK_LBUTTON = 0x01, //Left mouse button VK_RBUTTON = 0x02, //Right mouse button VK_CANCEL = 0x03, //Control-break processing VK_MBUTTON = 0x04, //Middle mouse button (three-button mouse) VK_BACK = 0x08, //BACKSPACE key VK_TAB = 0x09, //TAB key VK_CLEAR = 0x0C, //CLEAR key VK_RETURN = 0x0D, //ENTER key VK_SHIFT = 0x10, //SHIFT key VK_CONTROL = 0x11, //CTRL key VK_MENU = 0x12, //ALT key VK_PAUSE = 0x13, //PAUSE key VK_CAPITAL = 0x14, //CAPS LOCK key VK_HANGUL = 0x15, VK_ESCAPE = 0x1B, //ESC key VK_SPACE = 0x20, //SPACEBAR VK_PRIOR = 0x21, //PAGE UP key VK_NEXT = 0x22, //PAGE DOWN key VK_END = 0x23, //END key VK_HOME = 0x24, //HOME key VK_LEFT = 0x25, //LEFT ARROW key VK_UP = 0x26, //UP ARROW key VK_RIGHT = 0x27, //RIGHT ARROW key VK_DOWN = 0x28, //DOWN ARROW key VK_SELECT = 0x29, //SELECT key VK_PRINT = 0x2A, //PRINT key VK_EXECUTE = 0x2B, //EXECUTE key VK_SNAPSHOT = 0x2C, //PRINT SCREEN key VK_INSERT = 0x2D, //INS key VK_DELETE = 0x2E, //DEL key VK_HELP = 0x2F, //HELP key VK_0 = 0x30, //0 key VK_1 = 0x31, //1 key VK_2 = 0x32, //2 key VK_3 = 0x33, //3 key VK_4 = 0x34, //4 key VK_5 = 0x35, //5 key VK_6 = 0x36, //6 key VK_7 = 0x37, //7 key VK_8 = 0x38, //8 key VK_9 = 0x39, //9 key VK_A = 0x41, //A key VK_B = 0x42, //B key VK_C = 0x43, //C key VK_D = 0x44, //D key VK_E = 0x45, //E key VK_F = 0x46, //F key VK_G = 0x47, //G key VK_H = 0x48, //H key VK_I = 0x49, //I key VK_J = 0x4A, //J key VK_K = 0x4B, //K key VK_L = 0x4C, //L key VK_M = 0x4D, //M key VK_N = 0x4E, //N key VK_O = 0x4F, //O key VK_P = 0x50, //P key VK_Q = 0x51, //Q key VK_R = 0x52, //R key VK_S = 0x53, //S key VK_T = 0x54, //T key VK_U = 0x55, //U key VK_V = 0x56, //V key VK_W = 0x57, //W key VK_X = 0x58, //X key VK_Y = 0x59, //Y key VK_Z = 0x5A, //Z key VK_NUMPAD0 = 0x60, //Numeric keypad 0 key VK_NUMPAD1 = 0x61, //Numeric keypad 1 key VK_NUMPAD2 = 0x62, //Numeric keypad 2 key VK_NUMPAD3 = 0x63, //Numeric keypad 3 key VK_NUMPAD4 = 0x64, //Numeric keypad 4 key VK_NUMPAD5 = 0x65, //Numeric keypad 5 key VK_NUMPAD6 = 0x66, //Numeric keypad 6 key VK_NUMPAD7 = 0x67, //Numeric keypad 7 key VK_NUMPAD8 = 0x68, //Numeric keypad 8 key VK_NUMPAD9 = 0x69, //Numeric keypad 9 key VK_SEPARATOR = 0x6C, //Separator key VK_SUBTRACT = 0x6D, //Subtract key VK_DECIMAL = 0x6E, //Decimal key VK_DIVIDE = 0x6F, //Divide key VK_F1 = 0x70, //F1 key VK_F2 = 0x71, //F2 key VK_F3 = 0x72, //F3 key VK_F4 = 0x73, //F4 key VK_F5 = 0x74, //F5 key VK_F6 = 0x75, //F6 key VK_F7 = 0x76, //F7 key VK_F8 = 0x77, //F8 key VK_F9 = 0x78, //F9 key VK_F10 = 0x79, //F10 key VK_F11 = 0x7A, //F11 key VK_F12 = 0x7B, //F12 key VK_SCROLL = 0x91, //SCROLL LOCK key VK_LSHIFT = 0xA0, //Left SHIFT key VK_RSHIFT = 0xA1, //Right SHIFT key VK_LCONTROL = 0xA2, //Left CONTROL key VK_RCONTROL = 0xA3, //Right CONTROL key VK_LMENU = 0xA4, //Left MENU key VK_RMENU = 0xA5, //Right MENU key VK_PLAY = 0xFA, //Play key VK_ZOOM = 0xFB, //Zoom key } #endregion private LowLevelKeyboardProc _proc = hookProc; private static IntPtr hhook = IntPtr.Zero; public void SetHook() { IntPtr hInstance = LoadLibrary( "User32" ); hhook = SetWindowsHookEx(WH_KEYBOARD_LL, _proc, hInstance, 0); } public static void UnHook() { UnhookWindowsHookEx(hhook); } public static IntPtr hookProc( int code, IntPtr wParam, IntPtr lParam) { if (code >= 0 && wParam == (IntPtr)WM_KEYDOWN && CommonObj._keyCount <= 0) { int vkCode = Marshal.ReadInt32(lParam); //방향키나 엔터키 텝키 일경우에는 후킹 하지 않는다 VKeys vk_value = (VKeys)vkCode; switch (vk_value) { case VKeys.VK_RETURN: case VKeys.VK_TAB: case VKeys.VK_UP: case VKeys.VK_DOWN: case VKeys.VK_LEFT: case VKeys.VK_RIGHT: case VKeys.VK_LCONTROL: case VKeys.VK_RCONTROL: case VKeys.VK_DELETE: case VKeys.VK_HANGUL: case VKeys.VK_LSHIFT: case VKeys.VK_RSHIFT: return CallNextHookEx(hhook, code, ( int )wParam, lParam); } //사용자의 DataGrid를 EditMode로 전환 한다. _dataGrid.BeginEdit(); //후킹한 키보드를 강제로 입력 한다. keybd_event(( byte )Marshal.ReadByte(lParam), 0, KEYEVENTF_EXTENDEDKEY, 0); return (IntPtr)1; } else return CallNextHookEx(hhook, code, ( int )wParam, lParam); } #endregion |
SetHook() 을 호출하면 키보드 후킹이 시작되고, UnHook()를 호출하면 후킹이 종료 된다.
C#프로그램을 하다가 막히면 결국 WinApi를 사용해서 해결해야 하니, 아무래도 윈도우 Application 개발자는 C++(WinApi)을 기본적으로 알면 많은 도움이 될것 같다.