delorie.com/archives/browse.cgi   search  
Mail Archives: cygwin/2011/08/19/07:51:09

X-Recipient: archive-cygwin AT delorie DOT com
X-Spam-Check-By: sourceware.org
Date: Fri, 19 Aug 2011 13:50:19 +0200
From: Corinna Vinschen <corinna-cygwin AT cygwin DOT com>
To: cygwin AT cygwin DOT com
Subject: Re: Issue with inserting '@' at the command prompt.
Message-ID: <20110819115019.GA12612@calimero.vinschen.de>
Reply-To: cygwin AT cygwin DOT com
Mail-Followup-To: cygwin AT cygwin DOT com
References: <m3fwmammpu DOT fsf AT dalen DOT lamasti DOT net> <20110713130550 DOT GH13500 AT calimero DOT vinschen DOT de> <20110713133713 DOT GD4018 AT const> <20110713190028 DOT GA4742 AT calimero DOT vinschen DOT de> <m3bowxtgt9 DOT fsf AT dalen DOT lamasti DOT net> <20110714101609 DOT GF2125 AT calimero DOT vinschen DOT de> <20110714105621 DOT GJ2853 AT lamasti DOT net> <20110714124214 DOT GE5619 AT const> <20110819023740 DOT GL4919 AT type DOT famille DOT thibault DOT fr>
MIME-Version: 1.0
In-Reply-To: <20110819023740.GL4919@type.famille.thibault.fr>
User-Agent: Mutt/1.5.21 (2010-09-15)
Mailing-List: contact cygwin-help AT cygwin DOT com; run by ezmlm
List-Id: <cygwin.cygwin.com>
List-Unsubscribe: <mailto:cygwin-unsubscribe-archive-cygwin=delorie DOT com AT cygwin DOT com>
List-Subscribe: <mailto:cygwin-subscribe AT cygwin DOT com>
List-Archive: <http://sourceware.org/ml/cygwin/>
List-Post: <mailto:cygwin AT cygwin DOT com>
List-Help: <mailto:cygwin-help AT cygwin DOT com>, <http://sourceware.org/ml/#faqs>
Sender: cygwin-owner AT cygwin DOT com
Mail-Followup-To: cygwin AT cygwin DOT com
Delivered-To: mailing list cygwin AT cygwin DOT com

On Aug 19 04:37, Samuel Thibault wrote:
> Samuel Thibault, le Thu 14 Jul 2011 14:42:14 +0200, a écrit :
> > Lars Bjørndal, le Thu 14 Jul 2011 12:56:21 +0200, a écrit :
> > > BRLTTY has a cut & paste facility. It sometimes doesn't paste all
> > > characters inside cygwin. Pasting an att sign into a shell prompt, the
> > > terminal beeps, and no character is written. Doing the same thing
> > > after exiting bash, but still with BRLTTY running and in a cmd
> > > session, the att sign is printed.
> > 
> > I don't have the time to investigate now, but I can say that depending
> > on whether it could open the terminal through CONIN$, brltty uses
> > WriteConsoleInputW (or WriteConsoleInputA if not available) or SendInput
> > for this.
> 
> In the case at stake it is WriteConsoleInputW. Let me explain a simpler
> case (pasting is the same)
> 
> - the user presses '@' on his braille keyboard (ascii 0x40).
> - brltty wants to synthesize it.
> - brltty calls VkKeyScanW('@') to get the corresponding virtual key,
>   0x0630 on an azerty keyboard, which means altgr (controlkeystate 1) +
>   virtualkey 0x30
> - brltty calls MapVirtualKey(vk, 0) to get the corresponding scancode,
>   0x11 on a standard PC keyboard.
> - brltty thus calls WriteConsoleInputW, passing it a KEY_EVENT_RECORD
>   structure:
>   .bKeyDown = 1,
>   .wRepeatCount = 1,
>   .wVirtualKeyCode = 0x630,
>   .wVirtualScanCode = 0x11,
>   .uChar.UnicodeChar = 0x40,
>   .dwControlKeyState = 1,
> 
> and then the same with bKeyDown = 0.
> 
> This correctly inserts an '@' in a plain windows console with the
> windows cmd, but with a windows console with the cygwin or mingw shell,
> this beeps and does not insert anything.

I don't know why it works with cmd, but the above code is wrong.
The code returned by VkKeyScanW is not just a key code, it's the
combination of a key code in the low byte and a bitmask specifying
the modifier keys in the high byte, see
http://msdn.microsoft.com/en-us/library/ms646329%28VS.85%29.aspx

So, what I did was to write a simple testcase (wow!) which reproduces
your behaviour using the french keyboard layout.

Using the above virtual key code of 0xc630 and a control key state of 1
does not work.  However, computing a control code and a key code from
VkKeyScanW's return value works fine.

Here's the testcase:

$ cat > vkkeyscan-test.c <<EOF
#include <stdio.h>
#include <sys/ioctl.h>
#include <windows.h>

#define MAPVK_VK_TO_VSC    0
#define MAPVK_VSC_TO_VK    1
#define MAPVK_VK_TO_CHAR   2
#define MAPVK_VSC_TO_VK_EX 3
#define MAPVK_VK_TO_VSC_EX 4

void
write_char (WCHAR w, BOOL wrong, BOOL silent)
{
  SHORT vks = VkKeyScanW (w);
  UINT scan = MapVirtualKeyW (vks & 0xff, MAPVK_VK_TO_VSC);
  DWORD ctrl = 0;
  INPUT_RECORD in[2];
  DWORD ret;

  /* Create correct CtrlKeyState from high byte returned by VkKeyScanW. */
  if (vks & 0x100)
    ctrl |= SHIFT_PRESSED;
  if (vks & 0x200)
    ctrl |= RIGHT_CTRL_PRESSED;
  if (vks & 0x400)
    ctrl |= RIGHT_ALT_PRESSED;

  in[0].EventType = KEY_EVENT;
  in[0].Event.KeyEvent.bKeyDown = 1;
  in[0].Event.KeyEvent.wRepeatCount = 1;
  /* Only use lower byte from VkKeyScanW as key code. */
  if (wrong)
    in[0].Event.KeyEvent.wVirtualKeyCode = vks;
  else
    in[0].Event.KeyEvent.wVirtualKeyCode = vks & 0xff;
  in[0].Event.KeyEvent.wVirtualScanCode = scan;
  in[0].Event.KeyEvent.uChar.UnicodeChar = w;
  if (wrong)
    in[0].Event.KeyEvent.dwControlKeyState = 1;
  else
    in[0].Event.KeyEvent.dwControlKeyState = ctrl;
  memcpy (in + 1, in, sizeof (INPUT_RECORD));
  in[1].Event.KeyEvent.bKeyDown = 0;

  if (!silent)
    printf ("vks: 0x%hx, scan: 0x%x, vk: 0x%hx, ctrl: 0x%x\n",
	    vks, scan, in[0].Event.KeyEvent.wVirtualKeyCode,
	    in[0].Event.KeyEvent.dwControlKeyState);

  if (!WriteConsoleInputW (GetStdHandle (STD_INPUT_HANDLE), in, 2, &ret))
    fprintf (stderr, "WriteConsoleInput: %lu\n", GetLastError ());
}

int
main ()
{
  HKL layout;
  int nonblocking = 1;
  char buf[1];

  /* LANG_FRENCH | SUBLANG_FRENCH */
  layout = LoadKeyboardLayoutW (L"0000040c", KLF_ACTIVATE | KLF_REPLACELANG
					     | KLF_SETFORPROCESS);
  if (!layout)
    {
      fprintf (stderr, "LoadKeyboardLayout: %lu\n", GetLastError ());
      return 1;
    }
  /* nonblocking, so the user doesn't have to type anything. */
  ioctl (0, FIONBIO, &nonblocking);

  printf ("Wrong:\n");
  write_char (L'@', TRUE, FALSE);
  write_char (L'\n', TRUE, TRUE); /* Accommodate line buffered I/O. */
  if (read (0, buf, 1) > 0)
    printf ("read: 0x%x <%c>\n", buf[0], buf[0]);

  printf ("Right:\n");
  write_char (L'@', FALSE, FALSE);
  write_char (L'\n', FALSE, TRUE); /* Accommodate line buffered I/O. */
  if (read (0, buf, 1) > 0)
    printf ("read: 0x%x <%c>\n", buf[0], buf[0]);

  return 0;
}
EOF
$ gcc -g -o vkkeyscan-test vkkeyscan-test.c
$ ./vkkeyscan-test
Wrong:
vks: 0x630, scan: 0xb, vk: 0x630, ctrl: 0x1
read: 0x1b <
Right:
vks: 0x630, scan: 0xb, vk: 0x30, ctrl: 0x5
read: 0x40 <@>


Corinna


-- 
Corinna Vinschen                  Please, send mails regarding Cygwin to
Cygwin Project Co-Leader          cygwin AT cygwin DOT com
Red Hat

--
Problem reports:       http://cygwin.com/problems.html
FAQ:                   http://cygwin.com/faq/
Documentation:         http://cygwin.com/docs.html
Unsubscribe info:      http://cygwin.com/ml/#unsubscribe-simple

- Raw text -


  webmaster     delorie software   privacy  
  Copyright © 2019   by DJ Delorie     Updated Jul 2019