[please don't omit wine-devel when replying]
Stevie Trujillo stevie.trujillo@gmail.com wrote:
Stevie Trujillo stevie.trujillo@gmail.com wrote:
Another (minor) problem raised in the bugzilla entry is that, if a key is pressed when changing window, and released before returning, GetKeyboardState() will claim the key is still pressed (0x80). But this is easy to workaround, just hit the key again inside the game and it will stop scrolling.
dlls/winex11.drv/keyboard.c,X11DRV_KeymapNotify() should take care of that, if it doesn't - please debug why (probably a bug in your WM).
I think this function only applies to "modifier keys". It was tested with arrow keys.
It should work for all keys.
Anyway I don't think it's a big issue, since it doesn't cause any big problem, and it doesn't happen very often. It was just a situation where Windows and Wine exhibited slightly different behavior.
The first bug is much more annoying since one has to completely exit the game each time.
My comment was targeting both problems that you mentioned.
On Thu, 18 Apr 2013 17:39:33 +0900 Dmitry Timoshkov dmitry@baikal.ru wrote:
[please don't omit wine-devel when replying]
Stevie Trujillo stevie.trujillo@gmail.com wrote:
Stevie Trujillo stevie.trujillo@gmail.com wrote:
Another (minor) problem raised in the bugzilla entry is that, if a key is pressed when changing window, and released before returning, GetKeyboardState() will claim the key is still pressed (0x80). But this is easy to workaround, just hit the key again inside the game and it will stop scrolling.
dlls/winex11.drv/keyboard.c,X11DRV_KeymapNotify() should take care of that, if it doesn't - please debug why (probably a bug in your WM).
I think this function only applies to "modifier keys". It was tested with arrow keys.
It should work for all keys.
Anyway I don't think it's a big issue, since it doesn't cause any big problem, and it doesn't happen very often. It was just a situation where Windows and Wine exhibited slightly different behavior.
The first bug is much more annoying since one has to completely exit the game each time.
My comment was targeting both problems that you mentioned.
Ok, I didn't understand what this function does with the arrow keys yet, but I think I found out where the 0x40 comes from now:
In server/queue.c::update_input_key_state, down = (keystate == desktop->keystate) ? 0xc0 : 0x80;
When server/queue.c::set_input_key_state() is called with down=0, 0xc0 & ~0x80 = 0x40, keystate[key] &= ~0x80;
From dlls/winex11.drv/keyboard.c::X11DRV_KeymapNotify, get_async_key_state does SERVER_START_REQ( get_key_state ) with req->tid = 0. This retrieves the desktop->keystate.
When writing back changes, set_async_key_state calls SERVER_START_REQ( set_key_state ) with req->tid = GetCurrentThreadId(). This should copy the 0x40 bits from the desktop's keystate to the thread's keystate.
I tried to make a test case now. It's tested on wine-1.5.27 since I don't have enough battery to compile new wine.
$ winegcc test.c -o test
Issue1, the 0x40 bit: $ ./test.exe 00 00 00 00 00 00 00 00 *press LEFT arrow* 81 00 00 00 *release LEFT arrow* 01 00 00 00 *ALTTAB* 41 00 00 00
Issue2, LEFT ARROW remains pressed if released in another window. $ ./test.exe 00 00 00 00 *press LEFT ARROW* 81 00 00 00 *ALTTAB* c1 00 00 00 *RELEASE LEFT ARROW (outside Wine application)* c1 00 00 00 *ALTTAB BACK* c1 00 00 00 *press LEFT ARROW again (inside Wine application)* 41 00 00 00
test.c (also at http://pastie.org/7642788 if my mail client breaks it): // based on http://www.winprog.org/tutorial/simple_window.html #include <windows.h> #include <stdio.h>
static const char g_szClassName[] = "myWindowClass";
static void print_keyboard_state() { BYTE keystate[256]; GetKeyboardState(keystate); printf("%02x %02x %02x %02x\n", keystate[VK_LEFT], keystate[VK_UP], keystate[VK_RIGHT], keystate[VK_DOWN]); }
// Step 4: the Window Procedure static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch(msg) { case WM_TIMER: print_keyboard_state(); break; case WM_CLOSE: DestroyWindow(hwnd); break; case WM_DESTROY: PostQuitMessage(0); break; default: return DefWindowProc(hwnd, msg, wParam, lParam); } return 0; }
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { WNDCLASSEX wc; HWND hwnd; MSG Msg;
//Step 1: Registering the Window Class wc.cbSize = sizeof(WNDCLASSEX); wc.style = 0; wc.lpfnWndProc = WndProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = hInstance; wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); wc.lpszMenuName = NULL; wc.lpszClassName = g_szClassName; wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
if(!RegisterClassEx(&wc)) return 1;
// Step 2: Creating the Window hwnd = CreateWindowEx( WS_EX_CLIENTEDGE, g_szClassName, "The title of my window", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 240, 120, NULL, NULL, hInstance, NULL);
if(hwnd == NULL) return 1;
ShowWindow(hwnd, nCmdShow); UpdateWindow(hwnd);
UINT id; SetTimer(hwnd, 0, 1000, NULL);
// Step 3: The Message Loop while(GetMessage(&Msg, NULL, 0, 0) > 0) { TranslateMessage(&Msg); DispatchMessage(&Msg); } return Msg.wParam; }