mfc program input to focus

Recently, I need to realize the function of inputting characters to the current focus when I do a project of controlling a computer with a mobile phone. After checking for a long time, I finally completed it.

First of all, my idea is to simulate the mode of keyboard input. This method is very simple to implement by directly calling the function keybd_event. The keybd_event function has four parameters. The first parameter is the virtual keyboard value of windows, which is described in detail in msdn. Here are some commonly used and precautions. The virtual keyboard value of numbers is the corresponding ascii code, and the virtual keyboard value of lowercase letters is the corresponding ascii code. The key value is the ascii code corresponding to the uppercase letter. It is impossible to directly input the uppercase letter. You must first use the CAPSLOCK key to switch the uppercase, then enter the lowercase letter in the same way, and then don't forget to switch back. Enter, space and other virtual keyboard values ​​are available on the Internet. The key values ​​of commas, semicolons, brackets, etc. in the keyboard are VK_OEM_1-VK_OEM_7. The second parameter is not commonly used. The KEYEVENTF_KEYUP button pops up, which is the same as when we manually input letters, and the last one is set to zero to realize the input of 0:

keybd_event(‘0’, 0, 0 ,0);
keybd_event(‘0’, 0, KEYEVENTF_KEYUP ,0);

This seems very simple, but it has a lot of hidden dangers. I changed a computer and found that when I entered English, it was because the current input method was Sogou instead of the default input method, resulting in the loss of English instead of input. There are a lot of messy Chinese characters, so using this method to input English must make the current input method in English input state, and the second problem also follows, what to do when inputting Chinese, if you need to switch the input method state every time you enter It's too troublesome. The worst thing is that you don't know which input method to switch to when inputting Chinese (with Sogou, I believe no one wants to use smart abc). Later, I found a way to call up the Windows soft keyboard (osk.exe), However, the customer does not want to completely use the mouse to replace the keyboard operation, and hopes to have the keyboard operation process, so this idea is not feasible.

There is also an idea to use the GetForegroundWindow() function to get the handle of the current window of the system, so just do this:

HWND hWnd;
hWnd = ::GetForegroundWindow();

::SetWindowTextA(hWnd, "sad"); //输入sad

As a result, I changed the title name of the program, and did not implement the function of inputting at the focus, which is embarrassing.

It is natural to think that what I get is only the handle of the entire program, but the direction of our input is the current focus, so use the ::GetFocus() function to get the handle of the input focus, but there is still a problem, I only put my own application The name of a control in the program has been changed, but the focus has not changed. Take a closer look at msdn, it is clearly written to use the GetForegroundWindow () function to get the current window handle, the latter sentence is very strange, You can associate your thread's message queue with the windows owned by another thread by using the AttachThreadInput function. Translated to the effect That is, you can use the AttachThreadInput() function to connect the message queue of the current program thread with the messages owned by other threads in the system. It is really convincing without speaking. Baidu searched and found the reason. In fact, the GetFocus function can only get The input focus of the current program, if you want to obtain the input focus of other programs, you must bind the thread of the program executing the current system input focus with your own thread using the AttachThreadInput function .

HWND hWnd;
hWnd = ::GetForegroundWindow(); //Get the current window 
DWORD FormThreadID = GetCurrentThreadId(); //Thread id of this program
DWORD CWndThreadID = GetWindowThreadProcessId(hWnd, NULL); //The current program thread of the system
AttachThreadInput(CWndThreadID , FormThreadID, true);  //Bind
hWnd = ::GetFocus(); // Get the window where the keyboard cursor is currently  AttachThreadInput(CWndThreadID, FormThreadID, false); // Cancel 

At this time, you can use PostMessage() to send messages, of course SendMessage() is the same,

for(int i = 0; i < strl; i ++)//strl is the length of characters you want to enter

::PostMessage(hWnd, WM_CHAR, (WPARAM)buf[ i], NULL);

Sure enough, English can do it. The next step is to enter Chinese.

Since it is input from the mobile phone to the pc, the Chinese characters input from the mobile phone will be encoded by utf-8. If the Chinese characters are as realistic as this, the result will be that there is no Chinese character at all, and it is all messy symbols, because the program does not know whether you are Chinese or not. He will display it as a letter as usual. It is said on the Internet that buf and 0xff are an AND operation. After trying it, it can display Chinese characters, but the characters are wrong.

Then I found a problem, a Chinese character passed in is 3 bytes, and a Chinese character on my side only needs two bytes to display. After thinking about it carefully, I suddenly thought that because I want to be compatible with a large number of C codes, I did not use it. The Unicode character set uses a multi-byte character set, so character conversion must be implemented:

//utf-6 to Unicode

DWORD dwUnicodeLen; //Length of Unicode after conversion
TCHAR *pwText; //Pointer to save Unicode
dwUnicodeLen = MultiByteToWideChar(CP_UTF8,MB_ERR_INVALID_CHARS,kk,-1,NULL,0); //Calculate the length, pay attention to the second parameter and the reciprocal The second parameter
pwText = new TCHAR[dwUnicodeLen];

memset(pwText, 0, dwUnicodeLen * 2 + 2); //Unicode is two bytes representing a character

//Unicode to multibyte

int slen = WideCharToMultiByte(CP_ACP, 0, (LPWSTR)pwText, -1, NULL, 0, NULL, NULL);
char *szANSI=new char[slen + 1]; 
memset(szANSI, 0, slen + 1);
WideCharToMultiByte (CP_ACP, 0, (LPWSTR)pwText, -1, szANSI, slen, NULL,NULL);

Then you can send messages. I use vs2010. Careful children's shoes will notice that there is A or W behind SendMessage. A corresponds to multi-byte, and W corresponds to Unicode. Here is SendMessageA, and multi-byte can only be used. Send one byte at a time, and each character should be matched with 0xff:

for(int i = 0; i < slen; i ++)
::SendMessageA(hWnd, WM_CHAR, (WPARAM)(szANSI[i] & 0xff), NULL);

So far the whole function can be realized.


Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325403034&siteId=291194637