[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