[Rd] Rgui.exe 4.2.0 does not receive characters via the Windows API's PostMessage function

Tomas Kalibera tom@@@k@||ber@ @end|ng |rom gm@||@com
Tue May 24 09:34:54 CEST 2022


On 5/16/22 19:21, Tomas Kalibera wrote:
> Dear Jose,
>
> On 5/15/22 01:31, jcfaria wrote:
>> Dear Tomas,
>>
>> I am very grateful for your attention!
>>
>> I've been reading some things about the GraphApp 
>> toolkit(http://enchantia.com/software/graphapp/) that is being used 
>> in the development of new versions of Rgui.
>>
>> Really, if it's a matter of choice, the problems I reported cannot be 
>> considered a "bug". It's up to us - GUI and IDE application 
>> developers - to adapt to the new features.
>>
>> I'm studying how to get around the problem, but I still haven't found 
>> a simple way.
>>
>> The solution you proposed (code below) ran fine here in all versions 
>> of Rgui I have installed, but it's working only for very simple 
>> strings, like the one I tested. When testing the needs close to the 
>> real I found some problems.
>>
>> For example, when sending the string below:
>> - char *s = "(s <- c('á', 'b', 'c', 'í'))";
>>
>> Rgui receives:
>> > 9s ,- c9'', 'b', 'c', ''00
>> Error: unexpected symbol in "9s"
>> >
>>
>>
>> #include <windows.h>
>> #include <stdio.h>
>> #include <string.h>
>>
>> int main(int argc, char **argv) {
>>    HWND hw;
>>    int i, res;
>>
>>    printf("Getting Rgui window...\n");
>>    hw = FindWindow(NULL, "R Console (64-bit)");
>>
>>    printf("Got window: %x\n", hw);
>>    if (hw == NULL) {
>>      printf("Could not get Rgui window: %x\n", GetLastError());
>>      return 2;
>>    }
>>
>>    //Samples to send:
>> // char *s = "sd";
>>    char *s = "(s <- c('á', 'b', 'c', 'í'))";
>>
>>    for(i = 0; i < strlen(s); i++) {
>>      res = PostMessage(hw, WM_KEYDOWN, VkKeyScan(s[i]), 0);
>>      printf("Sending char %c: %d.\n", s[i], res);
>>    }
>>
>>    res = PostMessage(hw, WM_KEYDOWN, VK_RETURN, 0);
>>    printf("Sending return: %d\n.", res);
>>    return 0;
>> }
>>
>> The idea of Tinn-R communicating with Rgui.exe is to take advantage 
>> of the great stability of Rgui. Since communication with Rterm is 
>> done via pipe.
>>
>> I believe that developing a new interface using the resources of the 
>> R.dll library, as proposed, is outside the simple purposes of the 
>> Tinn-R project.
>>
>> Any help in this regard is welcome.
>
> If embedding R seems too involved, and the hack above doesn't work 
> well enough, perhaps you could use SendInput() (also mentioned in the 
> blog post [1] below as a more correct way to inject input as 
> WM_KEYDOWN).  This is an example:
>
> ---
>
> #include <windows.h>
> #include <stdio.h>
>
> int main(int argc, char **argv) {
>   HWND hw, ow;
>   int i, res;
>
>   hw = FindWindow(NULL, "R Console (64-bit)");
>   if (hw == NULL) {
>     printf("Could not get Rgui window: %x\n", GetLastError());
>     return 2;
>   }
>
>   ow = GetForegroundWindow();
>   if (ow == NULL)
>     printf("Foreground window is NULL\n");
>
>   if (!SetForegroundWindow(hw))
>     printf("Could not set Rgui as foreground window\n");
>
>   char *sd = "sd";
>   for(i = 0; i < strlen(sd); i++) {
>     INPUT input;
>
>     ZeroMemory(&input, sizeof(INPUT));
>     input.type = INPUT_KEYBOARD;
>     input.ki.dwFlags = KEYEVENTF_UNICODE;
>     input.ki.wScan = (unsigned) sd[i];
>     res = SendInput(1, &input, sizeof(INPUT));
>
>     printf("Sending char %c (%x): %d.\n", sd[i], sd[i], res);
>   }
>
>   {
>     INPUT input[2];
>
>     ZeroMemory(input, 2*sizeof(INPUT));
>     input[0].type = input[1].type = INPUT_KEYBOARD;
>     input[1].ki.dwFlags = KEYEVENTF_KEYUP;
>     input[0].ki.wVk = input[1].ki.wVk = VK_RETURN;
>     res = SendInput(2, input, sizeof(INPUT));
>     printf("Sending return: %d.\n", res);
>   }
>
>   if (!SetForegroundWindow(ow))
>     printf("Could not set the original window as foreground");
>
>   return 0;
> }

Dear Jose,

to send non-ASCII and repeated characters, you can modify the loop above 
as follows (use wchar_t to send Unicode characters, send also 
KEYEVENTF_KEYUP events to ensure that repeated characters such as ')' in 
the example are received). Otherwise, please refer to the MSDN 
documentation.

   wchar_t *sd = L"(s <- c('á', 'b', 'c', 'í'))";
   for(i = 0; i < wcslen(sd); i++) {
     INPUT input;

     ZeroMemory(&input, sizeof(INPUT));
     input.type = INPUT_KEYBOARD;
     input.ki.dwFlags = KEYEVENTF_UNICODE;
     input.ki.wScan = (unsigned) sd[i];
     res1 = SendInput(1, &input, sizeof(INPUT));

     ZeroMemory(&input, sizeof(INPUT));
     input.type = INPUT_KEYBOARD;
     input.ki.dwFlags = KEYEVENTF_UNICODE | KEYEVENTF_KEYUP;
     input.ki.wScan = (unsigned) sd[i];
     res2 = SendInput(1, &input, sizeof(INPUT));

     printf("Sending char %lc (%x): %d,%d .\n", sd[i], sd[i], res1, res2);
   }

Best
Tomas

>
> ---
>
> This example works for me with R 4.1.3 and with R-devel 82368. It 
> doesn't work with R 4.2.0 (see a related thread about Dasher on this 
> list).
>
> Best
> Tomas
>
>>
>> Best,
>> ///\\\///\\\///\\\///\\\///\\\///\\\///\\\///\\\///\\\///\\\
>> Jose Claudio Faria
>> UESC/DCET/Brasil
>> joseclaudio.faria at gmail.com
>> Telefones:
>> 55(73)3680.5545 - UESC
>> 55(73)99966.9100 - VIVO
>> ///\\\///\\\///\\\///\\\///\\\///\\\///\\\///\\\///\\\///\\\
>> If you have software to deal with statistics, you have arms,
>> if you have good software, you have arms and legs,
>> if you have software like R, you have arms, legs and wings...
>> the height of your flight depends only on you.
>>
>> ------ Mensagem original ------
>> De: "Tomas Kalibera" <tomas.kalibera using gmail.com>
>> Para: "jcfaria" <joseclaudio.faria using gmail.com>; "Duncan Murdoch" 
>> <murdoch.duncan using gmail.com>; r-devel using r-project.org
>> Enviado(s): 11/05/2022 13:32:23
>> Assunto: Re: [Rd] Rgui.exe 4.2.0 does not receive characters via the 
>> Windows API's PostMessage function
>>
>>>
>>> On 5/11/22 15:39, Tomas Kalibera wrote:
>>>>
>>>> On 5/11/22 08:15, Tomas Kalibera wrote:
>>>>>
>>>>> On 5/11/22 03:02, jcfaria wrote:
>>>>>> Dear Tomas,
>>>>>> I've tried, but I don't have the necessary C/C++ programming 
>>>>>> skills to fulfill your request.
>>>>>>
>>>>>> Maybe someone can help us by transcribing the little code in 
>>>>>> object Pascal that I sent to C/C++.
>>>>>>
>>>>>> If a small executable, made in Object Pascal, can help in your 
>>>>>> debug, I can provide.
>>>>>
>>>>> Dear Jose,
>>>>>
>>>>> no problem, I can try out with the Pascal code.
>>>>> Is there a free compiler I can use to build and run it?
>>>>
>>>> Actually I can reproduce it in a C program doing the same thing.
>>>>
>>>> The primary cause is that Rgui is using GraphApp Unicode windows on 
>>>> systems running in a multi-byte locale, which affects most systems 
>>>> since R 4.2 because of the switch to UTF-8. While Unicode windows 
>>>> have been used even in older versions of R, it was only on systems 
>>>> then running in a multi-byte locale, and apparently this hasn't 
>>>> been reported.
>>>>
>>>> When I modify R-devel to use non-Unicode GraphApp windows, the 
>>>> message sending works again. I will have a closer look, thanks for 
>>>> the report.
>>>
>>> I had a closer look and this doesn't really seem to be a bug in R to 
>>> me. For Unicode Windows, GraphApp uses WM_IME_COMPOSITION messages 
>>> to read the keys instead of WM_CHAR, which it uses for non-Unicode 
>>> windows. This is internal functionality of Rgui and a legitimate 
>>> choice. Rgui cannot simply handle both messages in Unicode windows, 
>>> because the characters would be doubled (if you see an easy, elegant 
>>> change to Rgui that would mimic the previous behavior, let me know). 
>>> This is certainly not a documented interface for Rgui, so I am 
>>> afraid you would have to change something in your application.
>>>
>>> I read that using PostMessage to simulate keyboard input is 
>>> considered wrong, see [1], and then one should instead use SendInput 
>>> (which then requires bringing the window to the foreground), if at 
>>> all simulating keyboard input. Maybe one could create a better 
>>> working solution that way, or using some automation library.
>>>
>>> As a quick hack, I found that [2] happens to be working on my 
>>> system, but again relying on the current implementation of Rgui 
>>> (simply you send WM_KEYDOWN also for the characters other than the 
>>> newline/return). It seems to be working also with R 4.1 for me.
>>>
>>> The usual way for GUIs/front-ends is to "embed" R, to link it as a 
>>> DLL. Rgui itself does it and also external applications such as 
>>> RStudio. Typically you would want to have a thin layer application 
>>> embedding R and make your GUI communicate with that, but switching 
>>> to that from sending the messages would require some work.
>>>
>>> Best
>>> Tomas
>>>
>>> [1] https://devblogs.microsoft.com/oldnewthing/20050530-11/?p=35513
>>>
>>> [2]
>>> #include <windows.h>
>>> #include <stdio.h>
>>> #include <string.h>
>>>
>>> int main(int argc, char **argv) {
>>>   HWND hw;
>>>   int i, res;
>>>
>>>   printf("Getting Rgui window...\n");
>>>   hw = FindWindow(NULL, "R Console (64-bit)");
>>>
>>>   printf("Got window: %x\n", hw);
>>>   if (hw == NULL) {
>>>     printf("Could not get Rgui window: %x\n", GetLastError());
>>>     return 2;
>>>   }
>>>
>>>   char *sd = "sd";
>>>   for(i = 0; i < strlen(sd); i++) {
>>>     res = PostMessage(hw, WM_KEYDOWN, VkKeyScan(sd[i]), 0);
>>>     printf("Sending char %c: %d.\n", sd[i], res);
>>>   }
>>>
>>>   res = PostMessage(hw, WM_KEYDOWN, VK_RETURN, 0);
>>>   printf("Sending return: %d\n.", res);
>>>   return 0;
>>> }
>>>
>>>
>>>>
>>>> For reference, to reproduce I ran
>>>>
>>>> Rgui --sdi
>>>>
>>>> and used this C example:
>>>>
>>>> #include <windows.h>
>>>> #include <stdio.h>
>>>> #include <string.h>
>>>>
>>>> int main(int argc, char **argv) {
>>>>   HWND hw;
>>>>   int i, res;
>>>>
>>>>   printf("Getting Rgui window...\n");
>>>>   hw = FindWindow(NULL, "R Console (64-bit)");
>>>>
>>>>   printf("Got window: %x\n", hw);
>>>>   if (hw == NULL) {
>>>>     printf("Could not get Rgui window: %x\n", GetLastError());
>>>>     return 2;
>>>>   }
>>>>
>>>>   char *sd = "sd";
>>>>   for(i = 0; i < strlen(sd); i++) {
>>>>     res = PostMessage(hw, WM_CHAR, (unsigned int) sd[i], 0);
>>>>     printf("Sending char %c: %d.\n", sd[i], res);
>>>>   }
>>>>
>>>>   res = PostMessage(hw, WM_KEYDOWN, VK_RETURN, 0);
>>>>   printf("Sending return: %d\n.", res);
>>>>   return 0;
>>>> }
>>>>
>>>> Best
>>>> Tomas
>>>>
>>>>
>>>>>
>>>>> Thanks
>>>>> Tomas
>>>>>
>>>>>>
>>>>>> Grateful for the attention,,
>>>>>> ///\\\///\\\///\\\///\\\///\\\///\\\///\\\///\\\///\\\///\\\
>>>>>> Jose Claudio Faria
>>>>>> UESC/DCET/Brasil
>>>>>> joseclaudio.faria at gmail.com
>>>>>> Telefones:
>>>>>> 55(73)3680.5545 - UESC
>>>>>> 55(73)99966.9100 - VIVO
>>>>>> ///\\\///\\\///\\\///\\\///\\\///\\\///\\\///\\\///\\\///\\\
>>>>>> If you have software to deal with statistics, you have arms,
>>>>>> if you have good software, you have arms and legs,
>>>>>> if you have software like R, you have arms, legs and wings...
>>>>>> the height of your flight depends only on you.
>>>>>>
>>>>>> ------ Mensagem original ------
>>>>>> De: "Tomas Kalibera" <tomas.kalibera using gmail.com>
>>>>>> Para: "jcfaria" <joseclaudio.faria using gmail.com>; "Duncan Murdoch" 
>>>>>> <murdoch.duncan using gmail.com>; r-devel using r-project.org
>>>>>> Enviado(s): 06/05/2022 04:24:44
>>>>>> Assunto: Re: [Rd] Rgui.exe 4.2.0 does not receive characters via 
>>>>>> the Windows API's PostMessage function
>>>>>>
>>>>>>>
>>>>>>> On 5/6/22 07:03, jcfaria wrote:
>>>>>>>> Dear Duncan,
>>>>>>>> I believe the problem is of a different nature.
>>>>>>>> I get TRUE 3 times running the code below:
>>>>>>>>
>>>>>>>> procedure TfMain.btnPasteClick(Sender: TObject);
>>>>>>>> var
>>>>>>>>   i: integer;
>>>>>>>>   sTmp: string;
>>>>>>>>   hBN: HWND;
>>>>>>>>   j: bool;
>>>>>>>>
>>>>>>>> begin
>>>>>>>>   hBN:= FindWindowA(nil,
>>>>>>>>                     'R Console (64-bit)');
>>>>>>>>
>>>>>>>>   sTmp:= 'sd';
>>>>>>>>
>>>>>>>>   for i:= 1 to Length(sTmp) do begin
>>>>>>>>     j:= PostMessage(hBN,
>>>>>>>>                     WM_CHAR,
>>>>>>>>                     Ord(sTmp[i]),
>>>>>>>>                     0);
>>>>>>>>
>>>>>>>>     ShowMessage(BoolToStr(j,
>>>>>>>>                           True));
>>>>>>>>   end;
>>>>>>>>
>>>>>>>>   j:= PostMessage(hBN,
>>>>>>>>               WM_KEYDOWN,
>>>>>>>>               VK_RETURN, 0);
>>>>>>>>
>>>>>>>>   ShowMessage(BoolToStr(j,
>>>>>>>>                         True));
>>>>>>>> end;
>>>>>>>>
>>>>>>>> That is, Rgui is receiving the message of the characters (via 
>>>>>>>> PostMessage), but it is blocking because it does not show them 
>>>>>>>> in the console.
>>>>>>>> The only thing Rgui blames is Carriage Return, as it adds an 
>>>>>>>> additional prompt with each run.
>>>>>>>
>>>>>>> I can't provide a good guess what impacted your use, but if you 
>>>>>>> could give me a full example, ideally in C, which can be 
>>>>>>> compiled with Rtools42 (so gcc, MinGW) and I can edit/recompile, 
>>>>>>> and works with R 4.1, I am happy to help debugging on 4.2.
>>>>>>>
>>>>>>> Rgui now uses GraphApp Unicode windows on systems where it 
>>>>>>> didn't before, because it uses UTF-8 also on systems it didn't 
>>>>>>> before (on systems that would use a single-byte locale in R 
>>>>>>> 4.1). These Unicode windows are a different code path and there 
>>>>>>> may be bugs not reported previously, including processing inputs 
>>>>>>> (recently I fixed handling of accents, for example). Otherwise 
>>>>>>> indeed R now uses UTF-8 as native encoding and UCRT as the C 
>>>>>>> runtime.
>>>>>>>
>>>>>>> Best
>>>>>>> Tomas
>>>>>>>
>>>>>>>
>>>>>>>>
>>>>>>>> >
>>>>>>>> >
>>>>>>>>
>>>>>>>> Best,
>>>>>>>> ///\\\///\\\///\\\///\\\///\\\///\\\///\\\///\\\///\\\///\\\
>>>>>>>> Jose Claudio Faria
>>>>>>>> UESC/DCET/Brasil
>>>>>>>> joseclaudio.faria at gmail.com
>>>>>>>> Telefones:
>>>>>>>> 55(73)3680.5545 - UESC
>>>>>>>> 55(73)99966.9100 - VIVO
>>>>>>>> ///\\\///\\\///\\\///\\\///\\\///\\\///\\\///\\\///\\\///\\\
>>>>>>>> If you have software to deal with statistics, you have arms,
>>>>>>>> if you have good software, you have arms and legs,
>>>>>>>> if you have software like R, you have arms, legs and wings...
>>>>>>>> the height of your flight depends only on you.
>>>>>>>>
>>>>>>>> ------ Mensagem original ------
>>>>>>>> De: "Duncan Murdoch" <murdoch.duncan using gmail.com>
>>>>>>>> Para: "jcfaria" <joseclaudio.faria using gmail.com>; 
>>>>>>>> r-devel using r-project.org
>>>>>>>> Enviado(s): 05/05/2022 13:17:53
>>>>>>>> Assunto: Re: [Rd] Rgui.exe 4.2.0 does not receive characters 
>>>>>>>> via the Windows API's PostMessage function
>>>>>>>>
>>>>>>>>> On 05/05/2022 11:17 a.m., jcfaria wrote:
>>>>>>>>>> Hello,
>>>>>>>>>>
>>>>>>>>>> Rgui.exe 4.2.0 does not receive characters via the Windows API's
>>>>>>>>>> PostMessage function.
>>>>>>>>>>
>>>>>>>>>> The Tinn-R project sends messages to Rgui.exe (SDI mode) via 
>>>>>>>>>> the Windows
>>>>>>>>>> API's PostMessage function.
>>>>>>>>>> A simplification of the code (in object Pascal) can be seen 
>>>>>>>>>> below.
>>>>>>>>>>
>>>>>>>>>> procedure TfMain.btnPasteClick(Sender: TObject);
>>>>>>>>>> var
>>>>>>>>>>     i: integer;
>>>>>>>>>>     sTmp: WideString;
>>>>>>>>>>     hBN: HWND;
>>>>>>>>>>
>>>>>>>>>> begin
>>>>>>>>>>     hBN:= FindWindowA(nil,
>>>>>>>>>>                       'R Console (64-bit)');
>>>>>>>>>>
>>>>>>>>>>     sTmp:= 'sd';
>>>>>>>>>>
>>>>>>>>>>     for i:= 1 to Length(sTmp) do begin
>>>>>>>>>>       PostMessage(hBN,
>>>>>>>>>>                   WM_CHAR,
>>>>>>>>>>                   Ord(sTmp[i]),
>>>>>>>>>>                   0);
>>>>>>>>>>     end;
>>>>>>>>>>
>>>>>>>>>>     PostMessage(hBN,
>>>>>>>>>>                 WM_KEYDOWN,
>>>>>>>>>>                 VK_RETURN, 0);
>>>>>>>>>> end;
>>>>>>>>>>
>>>>>>>>>> This code has always worked fine for all versions of Rgui.exe 
>>>>>>>>>> with the
>>>>>>>>>> exception of the last one released, ie 4.2.0.
>>>>>>>>>>
>>>>>>>>>> We've been trying to get around the problem on the Object 
>>>>>>>>>> Pascal side,
>>>>>>>>>> but without success so far.
>>>>>>>>>>
>>>>>>>>>> Does anyone connected to the compilation of Rqui.exe know 
>>>>>>>>>> what the
>>>>>>>>>> problem is?
>>>>>>>>>
>>>>>>>>> It could be that the new build enforces Windows security more 
>>>>>>>>> stringently.  More details are described in the answer to this 
>>>>>>>>> question: https://stackoverflow.com/a/40139498/2554330, but at 
>>>>>>>>> a minimum you should be checking the return value from 
>>>>>>>>> PostMessage.
>>>>>>>>>
>>>>>>>>> Duncan Murdoch
>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>> Best,
>>>>>>>>>> ///\\\///\\\///\\\///\\\///\\\///\\\///\\\///\\\///\\\///\\\
>>>>>>>>>> Jose Claudio Faria
>>>>>>>>>> UESC/DCET/Brasil
>>>>>>>>>> joseclaudio.faria at gmail.com
>>>>>>>>>> Telefones:
>>>>>>>>>> 55(73)3680.5545 - UESC
>>>>>>>>>> 55(73)99966.9100 - VIVO
>>>>>>>>>> ///\\\///\\\///\\\///\\\///\\\///\\\///\\\///\\\///\\\///\\\
>>>>>>>>>> If you have software to deal with statistics, you have arms,
>>>>>>>>>> if you have good software, you have arms and legs,
>>>>>>>>>> if you have software like R, you have arms, legs and wings...
>>>>>>>>>> the height of your flight depends only on you.
>>>>>>>>>>
>>>>>>>>>>     [[alternative HTML version deleted]]
>>>>>>>>>>
>>>>>>>>>> ______________________________________________
>>>>>>>>>> R-devel using r-project.org mailing list
>>>>>>>>>> https://stat.ethz.ch/mailman/listinfo/r-devel
>>>>>>>>>
>>>>>>>>
>>>>>>>> ______________________________________________
>>>>>>>> R-devel using r-project.org mailing list
>>>>>>>> https://stat.ethz.ch/mailman/listinfo/r-devel
>>>>>>
>>



More information about the R-devel mailing list