[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
Mon May 16 19:21:28 CEST 2022


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;
}

---

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