From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 11622 invoked by alias); 19 Aug 2011 14:07:11 -0000 Received: (qmail 11613 invoked by uid 22791); 19 Aug 2011 14:07:09 -0000 X-SWARE-Spam-Status: No, hits=-1.2 required=5.0 tests=AWL,BAYES_00 X-Spam-Check-By: sourceware.org Received: from solo.fdn.fr (HELO solo.fdn.fr) (80.67.169.19) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Fri, 19 Aug 2011 14:06:53 +0000 Received: from type.ipv6 (youpi.is-a-geek.org [80.67.176.89]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (Client did not present a certificate) by solo.fdn.fr (Postfix) with ESMTPS id C3F9B4416D for ; Fri, 19 Aug 2011 16:06:51 +0200 (CEST) Received: from samy by type.ipv6 with local (Exim 4.76) (envelope-from ) id 1QuPil-0005P0-54 for cygwin@cygwin.com; Fri, 19 Aug 2011 16:06:51 +0200 Date: Fri, 19 Aug 2011 14:07:00 -0000 From: Samuel Thibault To: cygwin@cygwin.com Subject: Re: Issue with inserting '@' at the command prompt. Message-ID: <20110819140651.GT4919@type.famille.thibault.fr> Mail-Followup-To: cygwin@cygwin.com References: <20110713130550.GH13500@calimero.vinschen.de> <20110713133713.GD4018@const> <20110713190028.GA4742@calimero.vinschen.de> <20110714101609.GF2125@calimero.vinschen.de> <20110714105621.GJ2853@lamasti.net> <20110714124214.GE5619@const> <20110819023740.GL4919@type.famille.thibault.fr> <20110819115019.GA12612@calimero.vinschen.de> <20110819131459.GO4919@type.famille.thibault.fr> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="7ZAtKRhVyVSsbBD2" Content-Disposition: inline Content-Transfer-Encoding: 8bit In-Reply-To: <20110819131459.GO4919@type.famille.thibault.fr> User-Agent: Mutt/1.5.21+34 (58baf7c9f32f) (2010-12-30) X-IsSubscribed: yes Mailing-List: contact cygwin-help@cygwin.com; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: cygwin-owner@cygwin.com Mail-Followup-To: cygwin@cygwin.com X-SW-Source: 2011-08/txt/msg00354.txt.bz2 --7ZAtKRhVyVSsbBD2 Content-Type: text/plain; charset=iso-8859-1 Content-Disposition: inline Content-Transfer-Encoding: 8bit Content-length: 1446 Corinna Vinschen, a écrit : > On Aug 19 15:14, Samuel Thibault wrote: > > Corinna Vinschen, le Fri 19 Aug 2011 13:50:19 +0200, a Ãcrit : > > > > .wVirtualKeyCode = 0x630, > > > > Eergl, no, that should have been 0x30 here, our code does properly masks > > out the high part, I just missed that in our code. > > And what about the control code? It's a fixed 1 in your example, That's only the example. 1 is obviously not hardcoded in the real source code, which I have attached (I just initially wanted to avoid you having to browse into the whole not-so-readable source ). > but obviously it should be 6. That's clearly not obvious from an altgr point of view: people use altgr to type '@', so it makes sense to simulate the hit of the right alt (i.e. altgr). > > Err, do you mean LEFT_ALT_PRESSED here? Right alt is altgr in some > > keyboard layouts, which is precisely what people use to type '@' in > > the french layout, actually. E.g. LeftAlt-A and RightAlt-A (i.e. > > I'm aware of this difference, so, no, that was a deliberate > RIGHT_ALT_PRESSED. But for the cases when only alt is to be pressed, this simulates a right alt, which with e.g. the french layout is not the same as the left one. > However, this also works for me when using > LEFT_CTRL_PRESSED and LEFT_ALT_PRESSED in the conditionals above. But it won't work with DOS applications (e.g. edit). That's precisely the reason why I added the special case. Samuel --7ZAtKRhVyVSsbBD2 Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="screen.c" Content-length: 17081 /* * BRLTTY - A background process providing access to the console screen (when in * text mode) for a blind person using a refreshable braille display. * * Copyright (C) 1995-2011 by The BRLTTY Developers. * * BRLTTY comes with ABSOLUTELY NO WARRANTY. * * This is free software, placed under the terms of the * GNU General Public License, as published by the Free Software * Foundation; either version 2 of the License, or (at your option) any * later version. Please see the file LICENSE-GPL for details. * * Web Page: http://mielke.cc/brltty/ * * This software is maintained by Dave Mielke . */ #include "prologue.h" #include "log.h" #include "parse.h" #include "brldefs.h" #include "sys_windows.h" #include "scancodes.h" #include "unicode.h" typedef enum { PARM_ROOT, PARM_FOLLOWFOCUS } ScreenParameters; #define SCRPARMS "root", "followfocus" static unsigned int root, followFocus; #include "scr_driver.h" static HANDLE consoleOutput = INVALID_HANDLE_VALUE; static HANDLE consoleInput = INVALID_HANDLE_VALUE; static int processParameters_WindowsScreen (char **parameters) { root = 0; if (*parameters[PARM_ROOT]) if (!validateYesNo(&root, parameters[PARM_ROOT])) logMessage(LOG_WARNING, "%s: %s", "invalid root setting", parameters[PARM_ROOT]); if (root && AttachConsoleProc) logMessage(LOG_WARNING, "No need for root BRLTTY on newer (XP or later) systems"); followFocus = 1; if (*parameters[PARM_FOLLOWFOCUS]) if (!validateYesNo(&followFocus, parameters[PARM_FOLLOWFOCUS])) logMessage(LOG_WARNING, "%s: %s", "invalid follow focus setting", parameters[PARM_FOLLOWFOCUS]); if (followFocus && !AttachConsoleProc) logMessage(LOG_WARNING, "Cannot follow focus on older (pre-XP) systems"); return 1; } static int openStdHandles (void) { if ((consoleOutput == INVALID_HANDLE_VALUE && (consoleOutput = CreateFile("CONOUT$",GENERIC_READ|GENERIC_WRITE,FILE_SHARE_READ|FILE_SHARE_WRITE,NULL,OPEN_EXISTING,0,NULL)) == INVALID_HANDLE_VALUE) ||(consoleInput == INVALID_HANDLE_VALUE && (consoleInput = CreateFile("CONIN$",GENERIC_READ|GENERIC_WRITE,FILE_SHARE_READ|FILE_SHARE_WRITE,NULL,OPEN_EXISTING,0,NULL)) == INVALID_HANDLE_VALUE)) { logWindowsSystemError("GetStdHandle"); return 0; } return 1; } static void closeStdHandles (void) { CloseHandle(consoleInput); consoleInput = INVALID_HANDLE_VALUE; CloseHandle(consoleOutput); consoleOutput = INVALID_HANDLE_VALUE; } static int tryToAttach (HWND win) { #define CONSOLEWINDOW "ConsoleWindowClass" static char class[] = CONSOLEWINDOW; DWORD process; if (GetClassName(win, class, sizeof(class)) != strlen(CONSOLEWINDOW) || memcmp(class,CONSOLEWINDOW,strlen(CONSOLEWINDOW))) return 0; if (!GetWindowThreadProcessId(win, &process)) return 0; FreeConsole(); if (!AttachConsoleProc(process)) return 0; closeStdHandles(); return openStdHandles(); } static int construct_WindowsScreen (void) { if (followFocus && (AttachConsoleProc || root)) { /* disable ^C */ SetConsoleCtrlHandler(NULL,TRUE); if (!FreeConsole() && GetLastError() != ERROR_INVALID_PARAMETER) logWindowsSystemError("FreeConsole"); return 1; } return openStdHandles(); } static void destruct_WindowsScreen (void) { closeStdHandles(); } static int selectVirtualTerminal_WindowsScreen (int vt) { return 0; } static int switchVirtualTerminal_WindowsScreen (int vt) { return 0; } static ALTTABINFO altTabInfo; static HWND altTab; static char altTabName[128]; static BOOL CALLBACK findAltTab (HWND win, LPARAM lparam) { if (GetAltTabInfoAProc(win, -1, &altTabInfo, NULL, 0)) { altTab = win; return FALSE; } return TRUE; } static CONSOLE_SCREEN_BUFFER_INFO info; static const char *unreadable; static int cols; static int rows; static int currentVirtualTerminal_WindowsScreen (void) { HWND win; unreadable = NULL; altTab = NULL; if (followFocus && (AttachConsoleProc || root) && GetAltTabInfoAProc) { altTabInfo.cbSize = sizeof(altTabInfo); EnumWindows(findAltTab, 0); if (altTab) { if (!(GetAltTabInfoAProc(altTab, altTabInfo.iColFocus + altTabInfo.iRowFocus * altTabInfo.cColumns, &altTabInfo, altTabName, sizeof(altTabName)))) { altTab = NULL; } else { return 0; } } } if (!(win = GetForegroundWindow())) win = INVALID_HANDLE_VALUE; if (!AttachConsoleProc && root) { unreadable = "root BRLTTY"; } else if (win == INVALID_HANDLE_VALUE) { unreadable = "no foreground window"; } else if (followFocus && AttachConsoleProc && !tryToAttach(win)) { unreadable = "no attachable console"; } else if (consoleOutput == INVALID_HANDLE_VALUE) { unreadable = "can't open console output"; } else if (!(GetConsoleScreenBufferInfo(consoleOutput, &info))) { logWindowsSystemError("GetConsoleScreenBufferInfo"); unreadable = "can't read console information"; CloseHandle(consoleOutput); consoleOutput = INVALID_HANDLE_VALUE; } return (int)win; } static void describe_WindowsScreen (ScreenDescription *description) { description->number = (int) currentVirtualTerminal_WindowsScreen(); description->unreadable = unreadable; if (unreadable) { description->rows = 1; description->cols = strlen(unreadable); description->posx = 0; description->posy = 0; description->cursor = 0; } else if (altTab) { description->rows = 1; description->cols = strlen(altTabName); description->posx = 0; description->posy = 0; description->cursor = 0; } else { description->cols = info.srWindow.Right + 1 - info.srWindow.Left; description->rows = info.srWindow.Bottom + 1 - info.srWindow.Top; description->posx = info.dwCursorPosition.X - info.srWindow.Left; description->posy = info.dwCursorPosition.Y - info.srWindow.Top; description->cursor = 1; } cols = description->cols; rows = description->rows; } static int readCharacters_WindowsScreen (const ScreenBox *box, ScreenCharacter *buffer) { int x, xx, y; static int wide; COORD coord; BOOL WINAPI (*fun) (HANDLE, void*, DWORD, COORD, LPDWORD); const char *name; size_t size; void *buf; WORD *bufAttr; if (!validateScreenBox(box, cols, rows)) return 0; if (unreadable) { setScreenMessage(box, buffer, unreadable); return 1; } if (altTab) { setScreenMessage(box, buffer, altTabName); return 1; } coord.X = box->left + info.srWindow.Left; coord.Y = box->top + info.srWindow.Top; if (!wide) { wchar_t buf; DWORD read; if (ReadConsoleOutputCharacterW(consoleOutput, &buf, 1, coord, &read)) wide = 1; else { if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) wide = -1; else { logWindowsSystemError("ReadConsoleOutputCharacterW"); return 0; } } } #define USE(f, t) (fun = (typeof(fun))f, name = #f, size = sizeof(t)) if (wide > 0) USE(ReadConsoleOutputCharacterW, wchar_t); else USE(ReadConsoleOutputCharacterA, char); #undef USE if (!(buf = malloc(box->width*size))) { logSystemError("malloc for Windows console reading"); return 0; } if (!(bufAttr = malloc(box->width*sizeof(WORD)))) { logSystemError("malloc for Windows console reading"); free(buf); return 0; } for (y=0; yheight; y++, coord.Y++) { DWORD read; if (!fun(consoleOutput, buf, box->width, coord, &read)) { logWindowsSystemError(name); break; } if (wide > 0) { for (x=0, xx = 0; xwidth && xx < read; x++, xx++) { wchar_t wc = ((wchar_t*)buf)[xx]; int i; buffer[y*box->width+x].text = wc; for (i = 1; i < getCharacterWidth(wc); i++) { x++; buffer[y*box->width+x].text = UNICODE_ZERO_WIDTH_SPACE; } } for ( ; xwidth; x++) { buffer[y*box->width+x].text = L' '; } } else { for (x=0; xwidth+x].text = ((char*)buf)[x]; } for ( ; xwidth; x++) { buffer[y*box->width+x].text = ' '; } } if (!ReadConsoleOutputAttribute(consoleOutput, bufAttr, box->width, coord, &read)) { logWindowsSystemError(name); break; } for (x=0, xx=0; xwidth && xx < read; x++, xx++) { int i; buffer[y*box->width+x].attributes = bufAttr[xx]; for (i = 1; i < getCharacterWidth(buffer[y*box->width+x].text); i++) { x++; buffer[y*box->width+x].attributes = bufAttr[xx]; } } for ( ; x < box->width; x++) buffer[y*box->width+x].attributes = 0; } free(buf); free(bufAttr); return (y == box->height); } static int doInsertWriteConsoleInput (BOOL down, WCHAR wchar, WORD vk, WORD scancode, DWORD controlKeyState) { DWORD num; INPUT_RECORD buf; KEY_EVENT_RECORD *keyE = &buf.Event.KeyEvent; buf.EventType = KEY_EVENT; memset(keyE, 0, sizeof(*keyE)); keyE->bKeyDown = down; keyE->wRepeatCount = 1; keyE->wVirtualKeyCode = vk; keyE->wVirtualScanCode = scancode; keyE->uChar.UnicodeChar = wchar; keyE->dwControlKeyState = controlKeyState; if (WriteConsoleInputW(consoleInput, &buf, 1, &num)) { if (num == 1) { return 1; } else { logMessage(LOG_ERR, "inserted %ld keys, expected 1", num); } } else { if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) { keyE->uChar.AsciiChar = wchar; if (WriteConsoleInputA(consoleInput, &buf, 1, &num)) { if (num == 1) { return 1; } else { logMessage(LOG_ERR, "inserted %ld keys, expected 1", num); } } } logWindowsSystemError("WriteConsoleInput"); CloseHandle(consoleInput); consoleInput = INVALID_HANDLE_VALUE; } return 0; } static int doInsertSendInput (BOOL down, WCHAR wchar, WORD vk, WORD scancode, DWORD flags) { if (SendInputProc) { UINT num; INPUT input; KEYBDINPUT *ki = &input.ki; input.type = INPUT_KEYBOARD; memset(ki, 0, sizeof(*ki)); ki->dwFlags = flags; if (wchar) { ki->wVk = 0; ki->wScan = wchar; ki->dwFlags |= KEYEVENTF_UNICODE; } else { ki->wVk = vk; ki->wScan = scancode; } if (!down) ki->dwFlags |= KEYEVENTF_KEYUP; num = SendInput(1, &input, sizeof(INPUT)); switch (num) { case 1: return 1; case 0: logWindowsSystemError("SendInput"); break; default: logMessage(LOG_ERR, "inserted %d keys, expected 1", num); break; } return 0; } else { keybd_event(vk, scancode, flags | (down ? 0 : KEYEVENTF_KEYUP), 0); return 1; } } static int insertKey_WindowsScreen (ScreenKey key) { SHORT vk = 0; SHORT scancode = 0; DWORD controlKeyState = 0; WCHAR wchar = 0; logMessage(LOG_DEBUG, "Insert key: %4.4X",key); if (isSpecialKey(key)) { switch (key & SCR_KEY_CHAR_MASK) { case SCR_KEY_ENTER: vk = VK_RETURN; wchar='\r'; break; case SCR_KEY_TAB: vk = VK_TAB; wchar='\t'; break; case SCR_KEY_BACKSPACE: vk = VK_BACK; wchar='\b'; break; case SCR_KEY_ESCAPE: vk = VK_ESCAPE; wchar='\e'; break; case SCR_KEY_CURSOR_LEFT: vk = VK_LEFT; break; case SCR_KEY_CURSOR_RIGHT: vk = VK_RIGHT; break; case SCR_KEY_CURSOR_UP: vk = VK_UP; break; case SCR_KEY_CURSOR_DOWN: vk = VK_DOWN; break; case SCR_KEY_PAGE_UP: vk = VK_PRIOR; break; case SCR_KEY_PAGE_DOWN: vk = VK_NEXT; break; case SCR_KEY_HOME: vk = VK_HOME; break; case SCR_KEY_END: vk = VK_END; break; case SCR_KEY_INSERT: vk = VK_INSERT; break; case SCR_KEY_DELETE: vk = VK_DELETE; break; case SCR_KEY_FUNCTION + 0: vk = VK_F1; break; case SCR_KEY_FUNCTION + 1: vk = VK_F2; break; case SCR_KEY_FUNCTION + 2: vk = VK_F3; break; case SCR_KEY_FUNCTION + 3: vk = VK_F4; break; case SCR_KEY_FUNCTION + 4: vk = VK_F5; break; case SCR_KEY_FUNCTION + 5: vk = VK_F6; break; case SCR_KEY_FUNCTION + 6: vk = VK_F7; break; case SCR_KEY_FUNCTION + 7: vk = VK_F8; break; case SCR_KEY_FUNCTION + 8: vk = VK_F9; break; case SCR_KEY_FUNCTION + 9: vk = VK_F10; break; case SCR_KEY_FUNCTION + 10: vk = VK_F11; break; case SCR_KEY_FUNCTION + 11: vk = VK_F12; break; case SCR_KEY_FUNCTION + 12: vk = VK_F13; break; case SCR_KEY_FUNCTION + 13: vk = VK_F14; break; case SCR_KEY_FUNCTION + 14: vk = VK_F15; break; case SCR_KEY_FUNCTION + 15: vk = VK_F16; break; case SCR_KEY_FUNCTION + 16: vk = VK_F17; break; case SCR_KEY_FUNCTION + 17: vk = VK_F18; break; case SCR_KEY_FUNCTION + 18: vk = VK_F19; break; case SCR_KEY_FUNCTION + 19: vk = VK_F20; break; case SCR_KEY_FUNCTION + 20: vk = VK_F21; break; case SCR_KEY_FUNCTION + 21: vk = VK_F22; break; case SCR_KEY_FUNCTION + 22: vk = VK_F23; break; case SCR_KEY_FUNCTION + 23: vk = VK_F24; break; default: logMessage(LOG_WARNING, "Key %4.4X not suported.", key); return 0; } } else { if (key & SCR_KEY_ALT_LEFT) { controlKeyState |= LEFT_ALT_PRESSED; key &= ~ SCR_KEY_ALT_LEFT; } if (key & SCR_KEY_ALT_RIGHT) { controlKeyState |= RIGHT_ALT_PRESSED; key &= ~ SCR_KEY_ALT_RIGHT; } if (key & SCR_KEY_SHIFT) { controlKeyState |= SHIFT_PRESSED; key &= ~ SCR_KEY_SHIFT; } if (key & SCR_KEY_CONTROL) { controlKeyState |= LEFT_CTRL_PRESSED; key &= ~ SCR_KEY_CONTROL; } wchar = key & SCR_KEY_CHAR_MASK; vk = VkKeyScanW(wchar); if (vk == -1 && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) vk = VkKeyScan(wchar); if (vk != -1) { logMessage(LOG_DEBUG, "vk is %4.4X", vk); if (vk & 0x100) controlKeyState |= SHIFT_PRESSED; if ((vk & 0x600) == 0x600) { controlKeyState |= RIGHT_ALT_PRESSED; } else { if (vk & 0x200) controlKeyState |= LEFT_CTRL_PRESSED; if (vk & 0x400) controlKeyState |= LEFT_ALT_PRESSED; } vk = vk & 0xff; } else vk = 0; } scancode = MapVirtualKey(vk, 0); logMessage(LOG_DEBUG,"wchar %x vk %x scancode %d ks %ld", wchar, vk, scancode, controlKeyState); if (consoleInput != INVALID_HANDLE_VALUE && !unreadable) { logMessage(LOG_DEBUG, "using WriteConsoleInput"); if (!doInsertWriteConsoleInput(TRUE, wchar, vk, scancode, controlKeyState)) return 0; if (!doInsertWriteConsoleInput(FALSE, wchar, vk, scancode, controlKeyState)) return 0; return 1; } else { logMessage(LOG_DEBUG, "using SendInput"); if (controlKeyState & LEFT_CTRL_PRESSED) if (!doInsertSendInput(TRUE, 0, VK_CONTROL, 0, 0)) return 0; if (controlKeyState & SHIFT_PRESSED) if (!doInsertSendInput(TRUE, 0, VK_SHIFT, 0, 0)) return 0; if (controlKeyState & LEFT_ALT_PRESSED) if (!doInsertSendInput(TRUE, 0, VK_MENU, 0, 0)) return 0; if (controlKeyState & RIGHT_ALT_PRESSED) if (!doInsertSendInput(TRUE, 0, VK_RMENU, 0, 0)) return 0; if (!doInsertSendInput(TRUE, wchar, vk, scancode, 0)) return 0; if (!doInsertSendInput(FALSE, wchar, vk, scancode, 0)) return 0; if (controlKeyState & RIGHT_ALT_PRESSED) if (!doInsertSendInput(FALSE, 0, VK_RMENU, 0, 0)) return 0; if (controlKeyState & LEFT_ALT_PRESSED) if (!doInsertSendInput(FALSE, 0, VK_MENU, 0, 0)) return 0; if (controlKeyState & SHIFT_PRESSED) if (!doInsertSendInput(FALSE, 0, VK_SHIFT, 0, 0)) return 0; if (controlKeyState & LEFT_CTRL_PRESSED) if (!doInsertSendInput(FALSE, 0, VK_CONTROL, 0, 0)) return 0; return 1; } return 0; } static int executeCommand_WindowsScreen (int command) { int blk = command & BRL_MSK_BLK; int arg = command & BRL_MSK_ARG; int press = 0; switch (blk) { case BRL_BLK_PASSXT: press = !(arg & 0X80); arg &= 0X7F; /* fallthrough */ case BRL_BLK_PASSAT: { press |= !(command & BRL_FLG_KBD_RELEASE); if (arg >= 0X80) return 0; if (command & BRL_FLG_KBD_EMUL1) return 0; if (blk == BRL_BLK_PASSAT) arg = at2Xt[arg]; return doInsertSendInput (press, 0, 0, arg, command & BRL_FLG_KBD_EMUL0 ? KEYEVENTF_EXTENDEDKEY : 0); } } return 0; } static void scr_initialize (MainScreen *main) { initializeRealScreen(main); main->base.selectVirtualTerminal = selectVirtualTerminal_WindowsScreen; main->base.switchVirtualTerminal = switchVirtualTerminal_WindowsScreen; main->base.currentVirtualTerminal = currentVirtualTerminal_WindowsScreen; main->base.describe = describe_WindowsScreen; main->base.readCharacters = readCharacters_WindowsScreen; main->base.insertKey = insertKey_WindowsScreen; main->base.executeCommand = executeCommand_WindowsScreen; main->processParameters = processParameters_WindowsScreen; main->construct = construct_WindowsScreen; main->destruct = destruct_WindowsScreen; } --7ZAtKRhVyVSsbBD2 Content-Type: text/plain; charset=us-ascii Content-length: 218 -- 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 --7ZAtKRhVyVSsbBD2--