input.c 39 KB
Newer Older
1 2 3 4
/*
 * USER Input processing
 *
 * Copyright 1993 Bob Amstadt
5
 * Copyright 1996 Albrecht Kleine
6 7 8 9
 * Copyright 1997 David Faure
 * Copyright 1998 Morten Welinder
 * Copyright 1998 Ulrich Weigand
 *
10 11 12 13 14 15 16 17 18 19 20 21
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
22
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 24
 */

Steven Edwards's avatar
Steven Edwards committed
25 26 27
#include "config.h"
#include "wine/port.h"

28 29
#include <stdlib.h>
#include <string.h>
30
#include <stdarg.h>
31
#include <stdio.h>
32 33 34
#include <ctype.h>
#include <assert.h>

35 36
#define NONAMELESSUNION
#define NONAMELESSSTRUCT
37 38
#include "ntstatus.h"
#define WIN32_NO_STATUS
39
#include "windef.h"
40
#include "winbase.h"
41
#include "wingdi.h"
42
#include "winuser.h"
43
#include "winnls.h"
44
#include "winternl.h"
45
#include "winerror.h"
46 47 48 49
#include "win.h"
#include "user_private.h"
#include "wine/server.h"
#include "wine/debug.h"
50
#include "wine/unicode.h"
51

52
WINE_DEFAULT_DEBUG_CHANNEL(win);
53
WINE_DECLARE_DEBUG_CHANNEL(keyboard);
54

55

56 57 58 59 60 61 62
/***********************************************************************
 *           get_key_state
 */
static WORD get_key_state(void)
{
    WORD ret = 0;

63
    if (GetSystemMetrics( SM_SWAPBUTTON ))
64
    {
65 66
        if (GetAsyncKeyState(VK_RBUTTON) & 0x80) ret |= MK_LBUTTON;
        if (GetAsyncKeyState(VK_LBUTTON) & 0x80) ret |= MK_RBUTTON;
67 68 69
    }
    else
    {
70 71
        if (GetAsyncKeyState(VK_LBUTTON) & 0x80) ret |= MK_LBUTTON;
        if (GetAsyncKeyState(VK_RBUTTON) & 0x80) ret |= MK_RBUTTON;
72
    }
73 74 75 76 77
    if (GetAsyncKeyState(VK_MBUTTON) & 0x80)  ret |= MK_MBUTTON;
    if (GetAsyncKeyState(VK_SHIFT) & 0x80)    ret |= MK_SHIFT;
    if (GetAsyncKeyState(VK_CONTROL) & 0x80)  ret |= MK_CONTROL;
    if (GetAsyncKeyState(VK_XBUTTON1) & 0x80) ret |= MK_XBUTTON1;
    if (GetAsyncKeyState(VK_XBUTTON2) & 0x80) ret |= MK_XBUTTON2;
78 79 80 81
    return ret;
}


82 83 84 85 86 87 88 89 90 91 92 93 94 95
/**********************************************************************
 *		set_capture_window
 */
BOOL set_capture_window( HWND hwnd, UINT gui_flags, HWND *prev_ret )
{
    HWND previous = 0;
    UINT flags = 0;
    BOOL ret;

    if (gui_flags & GUI_INMENUMODE) flags |= CAPTURE_MENU;
    if (gui_flags & GUI_INMOVESIZE) flags |= CAPTURE_MOVESIZE;

    SERVER_START_REQ( set_capture_window )
    {
96
        req->handle = wine_server_user_handle( hwnd );
97 98 99
        req->flags  = flags;
        if ((ret = !wine_server_call_err( req )))
        {
100 101
            previous = wine_server_ptr_handle( reply->previous );
            hwnd = wine_server_ptr_handle( reply->full_handle );
102 103 104 105
        }
    }
    SERVER_END_REQ;

106 107 108
    if (ret)
    {
        USER_Driver->pSetCapture( hwnd, gui_flags );
109

110 111
        if (previous && previous != hwnd)
            SendMessageW( previous, WM_CAPTURECHANGED, 0, (LPARAM)hwnd );
112

113 114
        if (prev_ret) *prev_ret = previous;
    }
115 116 117 118
    return ret;
}


119 120 121 122 123
/***********************************************************************
 *		__wine_send_input  (USER32.@)
 *
 * Internal SendInput function to allow the graphics driver to inject real events.
 */
124
BOOL CDECL __wine_send_input( HWND hwnd, const INPUT *input )
125
{
126
    NTSTATUS status = send_hardware_message( hwnd, input, 0 );
127 128 129 130 131
    if (status) SetLastError( RtlNtStatusToDosError(status) );
    return !status;
}


132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167
/***********************************************************************
 *		update_mouse_coords
 *
 * Helper for SendInput.
 */
static void update_mouse_coords( INPUT *input )
{
    if (!(input->u.mi.dwFlags & MOUSEEVENTF_MOVE)) return;

    if (input->u.mi.dwFlags & MOUSEEVENTF_ABSOLUTE)
    {
        input->u.mi.dx = (input->u.mi.dx * GetSystemMetrics( SM_CXSCREEN )) >> 16;
        input->u.mi.dy = (input->u.mi.dy * GetSystemMetrics( SM_CYSCREEN )) >> 16;
    }
    else
    {
        int accel[3];

        /* dx and dy can be negative numbers for relative movements */
        SystemParametersInfoW(SPI_GETMOUSE, 0, accel, 0);

        if (!accel[2]) return;

        if (abs(input->u.mi.dx) > accel[0])
        {
            input->u.mi.dx *= 2;
            if ((abs(input->u.mi.dx) > accel[1]) && (accel[2] == 2)) input->u.mi.dx *= 2;
        }
        if (abs(input->u.mi.dy) > accel[0])
        {
            input->u.mi.dy *= 2;
            if ((abs(input->u.mi.dy) > accel[1]) && (accel[2] == 2)) input->u.mi.dy *= 2;
        }
    }
}

168 169 170 171 172
/***********************************************************************
 *		SendInput  (USER32.@)
 */
UINT WINAPI SendInput( UINT count, LPINPUT inputs, int size )
{
173 174
    UINT i;
    NTSTATUS status;
175

176 177 178
    for (i = 0; i < count; i++)
    {
        if (inputs[i].type == INPUT_MOUSE)
179
        {
180 181 182
            /* we need to update the coordinates to what the server expects */
            INPUT input = inputs[i];
            update_mouse_coords( &input );
183
            status = send_hardware_message( 0, &input, SEND_HWMSG_INJECTED );
184
        }
185 186 187 188 189 190 191
        else status = send_hardware_message( 0, &inputs[i], SEND_HWMSG_INJECTED );

        if (status)
        {
            SetLastError( RtlNtStatusToDosError(status) );
            break;
        }
192 193
    }

194
    return i;
195 196 197 198 199 200 201
}


/***********************************************************************
 *		keybd_event (USER32.@)
 */
void WINAPI keybd_event( BYTE bVk, BYTE bScan,
202
                         DWORD dwFlags, ULONG_PTR dwExtraInfo )
203 204 205 206 207 208 209
{
    INPUT input;

    input.type = INPUT_KEYBOARD;
    input.u.ki.wVk = bVk;
    input.u.ki.wScan = bScan;
    input.u.ki.dwFlags = dwFlags;
210
    input.u.ki.time = 0;
211
    input.u.ki.dwExtraInfo = dwExtraInfo;
212 213 214 215
    SendInput( 1, &input, sizeof(input) );
}


216
/***********************************************************************
217
 *		mouse_event (USER32.@)
218 219
 */
void WINAPI mouse_event( DWORD dwFlags, DWORD dx, DWORD dy,
220
                         DWORD dwData, ULONG_PTR dwExtraInfo )
221
{
222 223 224 225 226 227 228
    INPUT input;

    input.type = INPUT_MOUSE;
    input.u.mi.dx = dx;
    input.u.mi.dy = dy;
    input.u.mi.mouseData = dwData;
    input.u.mi.dwFlags = dwFlags;
229
    input.u.mi.time = 0;
230 231
    input.u.mi.dwExtraInfo = dwExtraInfo;
    SendInput( 1, &input, sizeof(input) );
232 233
}

234

235
/***********************************************************************
236
 *		GetCursorPos (USER32.@)
237
 */
238
BOOL WINAPI DECLSPEC_HOTPATCH GetCursorPos( POINT *pt )
239
{
240 241
    BOOL ret;
    DWORD last_change;
242

243
    if (!pt) return FALSE;
244 245 246 247 248 249 250

    SERVER_START_REQ( set_cursor )
    {
        if ((ret = !wine_server_call( req )))
        {
            pt->x = reply->new_x;
            pt->y = reply->new_y;
251
            last_change = reply->last_change;
252 253 254
        }
    }
    SERVER_END_REQ;
255 256 257

    /* query new position from graphics driver if we haven't updated recently */
    if (ret && GetTickCount() - last_change > 100) ret = USER_Driver->pGetCursorPos( pt );
258
    return ret;
259 260 261
}


Per Nystrom's avatar
Per Nystrom committed
262 263 264 265 266
/***********************************************************************
 *		GetCursorInfo (USER32.@)
 */
BOOL WINAPI GetCursorInfo( PCURSORINFO pci )
{
267 268
    BOOL ret;

Per Nystrom's avatar
Per Nystrom committed
269
    if (!pci) return 0;
270 271 272 273 274 275 276 277 278 279 280

    SERVER_START_REQ( get_thread_input )
    {
        req->tid = 0;
        if ((ret = !wine_server_call( req )))
        {
            pci->hCursor = wine_server_ptr_handle( reply->cursor );
            pci->flags = (reply->show_count >= 0) ? CURSOR_SHOWING : 0;
        }
    }
    SERVER_END_REQ;
Per Nystrom's avatar
Per Nystrom committed
281
    GetCursorPos(&pci->ptScreenPos);
282
    return ret;
Per Nystrom's avatar
Per Nystrom committed
283 284 285
}


286 287 288
/***********************************************************************
 *		SetCursorPos (USER32.@)
 */
289
BOOL WINAPI DECLSPEC_HOTPATCH SetCursorPos( INT x, INT y )
290
{
291
    BOOL ret;
292
    INT prev_x, prev_y, new_x, new_y;
293 294 295 296 297 298 299 300

    SERVER_START_REQ( set_cursor )
    {
        req->flags = SET_CURSOR_POS;
        req->x     = x;
        req->y     = y;
        if ((ret = !wine_server_call( req )))
        {
301 302 303 304
            prev_x = reply->prev_x;
            prev_y = reply->prev_y;
            new_x  = reply->new_x;
            new_y  = reply->new_y;
305 306 307
        }
    }
    SERVER_END_REQ;
308
    if (ret && (prev_x != new_x || prev_y != new_y)) USER_Driver->pSetCursorPos( new_x, new_y );
309
    return ret;
310 311 312
}


313
/**********************************************************************
314
 *		SetCapture (USER32.@)
315
 */
316
HWND WINAPI DECLSPEC_HOTPATCH SetCapture( HWND hwnd )
317
{
318
    HWND previous = 0;
319

320
    set_capture_window( hwnd, 0, &previous );
321
    return previous;
322 323 324 325
}


/**********************************************************************
Patrik Stridvall's avatar
Patrik Stridvall committed
326
 *		ReleaseCapture (USER32.@)
327
 */
328
BOOL WINAPI DECLSPEC_HOTPATCH ReleaseCapture(void)
329
{
330
    BOOL ret = set_capture_window( 0, 0, NULL );
331 332

    /* Somebody may have missed some mouse movements */
333
    if (ret) mouse_event( MOUSEEVENTF_MOVE, 0, 0, 0, 0 );
334

335
    return ret;
336 337 338 339
}


/**********************************************************************
340
 *		GetCapture (USER32.@)
341
 */
342
HWND WINAPI GetCapture(void)
343
{
344 345 346 347 348
    HWND ret = 0;

    SERVER_START_REQ( get_thread_input )
    {
        req->tid = GetCurrentThreadId();
349
        if (!wine_server_call_err( req )) ret = wine_server_ptr_handle( reply->capture );
350 351 352
    }
    SERVER_END_REQ;
    return ret;
353 354
}

355

356
/**********************************************************************
357
 *		GetAsyncKeyState (USER32.@)
358
 *
359
 *	Determine if a key is or was pressed.  retval has high-order
360 361 362
 * bit set to 1 if currently pressed, low-order bit set to 1 if key has
 * been pressed.
 */
363
SHORT WINAPI DECLSPEC_HOTPATCH GetAsyncKeyState( INT key )
364
{
365
    struct user_thread_info *thread_info = get_user_thread_info();
366 367 368 369 370 371
    SHORT ret;

    if (key < 0 || key >= 256) return 0;

    if ((ret = USER_Driver->pGetAsyncKeyState( key )) == -1)
    {
372 373 374 375 376 377
        if (thread_info->key_state &&
            !(thread_info->key_state[key] & 0xc0) &&
            GetTickCount() - thread_info->key_state_time < 50)
            return 0;

        if (!thread_info->key_state) thread_info->key_state = HeapAlloc( GetProcessHeap(), 0, 256 );
378

379 380 381 382 383
        ret = 0;
        SERVER_START_REQ( get_key_state )
        {
            req->tid = 0;
            req->key = key;
384
            if (thread_info->key_state) wine_server_set_reply( req, thread_info->key_state, 256 );
385 386 387 388
            if (!wine_server_call( req ))
            {
                if (reply->state & 0x40) ret |= 0x0001;
                if (reply->state & 0x80) ret |= 0x8000;
389
                thread_info->key_state_time = GetTickCount();
390 391 392 393 394
            }
        }
        SERVER_END_REQ;
    }
    return ret;
395 396
}

Ulrich Weigand's avatar
Ulrich Weigand committed
397

398 399 400 401 402 403 404
/***********************************************************************
 *		GetQueueStatus (USER32.@)
 */
DWORD WINAPI GetQueueStatus( UINT flags )
{
    DWORD ret = 0;

405 406 407 408 409
    if (flags & ~(QS_ALLINPUT | QS_ALLPOSTMESSAGE | QS_SMRESULT))
    {
        SetLastError( ERROR_INVALID_FLAGS );
        return 0;
    }
410

411
    /* check for pending X events */
412
    USER_Driver->pMsgWaitForMultipleObjectsEx( 0, NULL, 0, flags, 0 );
413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432

    SERVER_START_REQ( get_queue_status )
    {
        req->clear = 1;
        wine_server_call( req );
        ret = MAKELONG( reply->changed_bits & flags, reply->wake_bits & flags );
    }
    SERVER_END_REQ;
    return ret;
}


/***********************************************************************
 *		GetInputState   (USER32.@)
 */
BOOL WINAPI GetInputState(void)
{
    DWORD ret = 0;

    /* check for pending X events */
433
    USER_Driver->pMsgWaitForMultipleObjectsEx( 0, NULL, 0, QS_INPUT, 0 );
434 435 436 437 438 439 440 441 442 443 444 445

    SERVER_START_REQ( get_queue_status )
    {
        req->clear = 0;
        wine_server_call( req );
        ret = reply->wake_bits & (QS_KEY | QS_MOUSEBUTTON);
    }
    SERVER_END_REQ;
    return ret;
}


446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471
/******************************************************************
 *              GetLastInputInfo (USER32.@)
 */
BOOL WINAPI GetLastInputInfo(PLASTINPUTINFO plii)
{
    BOOL ret;

    TRACE("%p\n", plii);

    if (plii->cbSize != sizeof (*plii) )
    {
        SetLastError(ERROR_INVALID_PARAMETER);
        return FALSE;
    }

    SERVER_START_REQ( get_last_input_time )
    {
        ret = !wine_server_call_err( req );
        if (ret)
            plii->dwTime = reply->time;
    }
    SERVER_END_REQ;
    return ret;
}


472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488
/******************************************************************
*		GetRawInputDeviceList (USER32.@)
*/
UINT WINAPI GetRawInputDeviceList(PRAWINPUTDEVICELIST pRawInputDeviceList, PUINT puiNumDevices, UINT cbSize)
{
    FIXME("(pRawInputDeviceList=%p, puiNumDevices=%p, cbSize=%d) stub!\n", pRawInputDeviceList, puiNumDevices, cbSize);

    if(pRawInputDeviceList)
        memset(pRawInputDeviceList, 0, sizeof *pRawInputDeviceList);
    *puiNumDevices = 0;
    return 0;
}


/******************************************************************
*		RegisterRawInputDevices (USER32.@)
*/
489
BOOL WINAPI DECLSPEC_HOTPATCH RegisterRawInputDevices(RAWINPUTDEVICE *devices, UINT device_count, UINT size)
490
{
491 492 493 494 495
    struct rawinput_device *d;
    BOOL ret;
    UINT i;

    TRACE("devices %p, device_count %u, size %u.\n", devices, device_count, size);
496

497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528
    if (size != sizeof(*devices))
    {
        WARN("Invalid structure size %u.\n", size);
        return FALSE;
    }

    if (!(d = HeapAlloc( GetProcessHeap(), 0, device_count * sizeof(*d) ))) return FALSE;

    for (i = 0; i < device_count; ++i)
    {
        TRACE("device %u: page %#x, usage %#x, flags %#x, target %p.\n",
                i, devices[i].usUsagePage, devices[i].usUsage,
                devices[i].dwFlags, devices[i].hwndTarget);
        if (devices[i].dwFlags & ~RIDEV_REMOVE)
            FIXME("Unhandled flags %#x for device %u.\n", devices[i].dwFlags, i);

        d[i].usage_page = devices[i].usUsagePage;
        d[i].usage = devices[i].usUsage;
        d[i].flags = devices[i].dwFlags;
        d[i].target = wine_server_user_handle( devices[i].hwndTarget );
    }

    SERVER_START_REQ( update_rawinput_devices )
    {
        wine_server_add_data( req, d, device_count * sizeof(*d) );
        ret = !wine_server_call( req );
    }
    SERVER_END_REQ;

    HeapFree( GetProcessHeap(), 0, d );

    return ret;
529 530 531 532 533 534
}


/******************************************************************
*		GetRawInputData (USER32.@)
*/
535
UINT WINAPI GetRawInputData(HRAWINPUT rawinput, UINT command, void *data, UINT *data_size, UINT header_size)
536
{
537 538
    RAWINPUT *ri = (RAWINPUT *)rawinput;
    UINT s;
539

540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569
    TRACE("rawinput %p, command %#x, data %p, data_size %p, header_size %u.\n",
            rawinput, command, data, data_size, header_size);

    if (header_size != sizeof(RAWINPUTHEADER))
    {
        WARN("Invalid structure size %u.\n", header_size);
        return ~0U;
    }

    switch (command)
    {
    case RID_INPUT:
        s = ri->header.dwSize;
        break;
    case RID_HEADER:
        s = sizeof(RAWINPUTHEADER);
        break;
    default:
        return ~0U;
    }

    if (!data)
    {
        *data_size = s;
        return 0;
    }

    if (*data_size < s) return ~0U;
    memcpy(data, ri, s);
    return s;
570 571 572 573 574 575
}


/******************************************************************
*		GetRawInputBuffer (USER32.@)
*/
576
UINT WINAPI DECLSPEC_HOTPATCH GetRawInputBuffer(PRAWINPUT pData, PUINT pcbSize, UINT cbSizeHeader)
577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627
{
    FIXME("(pData=%p, pcbSize=%p, cbSizeHeader=%d) stub!\n", pData, pcbSize, cbSizeHeader);

    return 0;
}


/******************************************************************
*		GetRawInputDeviceInfoA (USER32.@)
*/
UINT WINAPI GetRawInputDeviceInfoA(HANDLE hDevice, UINT uiCommand, LPVOID pData, PUINT pcbSize)
{
    FIXME("(hDevice=%p, uiCommand=%d, pData=%p, pcbSize=%p) stub!\n", hDevice, uiCommand, pData, pcbSize);

    return 0;
}


/******************************************************************
*		GetRawInputDeviceInfoW (USER32.@)
*/
UINT WINAPI GetRawInputDeviceInfoW(HANDLE hDevice, UINT uiCommand, LPVOID pData, PUINT pcbSize)
{
    FIXME("(hDevice=%p, uiCommand=%d, pData=%p, pcbSize=%p) stub!\n", hDevice, uiCommand, pData, pcbSize);

    return 0;
}


/******************************************************************
*		GetRegisteredRawInputDevices (USER32.@)
*/
UINT WINAPI GetRegisteredRawInputDevices(PRAWINPUTDEVICE pRawInputDevices, PUINT puiNumDevices, UINT cbSize)
{
    FIXME("(pRawInputDevices=%p, puiNumDevices=%p, cbSize=%d) stub!\n", pRawInputDevices, puiNumDevices, cbSize);

    return 0;
}


/******************************************************************
*		DefRawInputProc (USER32.@)
*/
LRESULT WINAPI DefRawInputProc(PRAWINPUT *paRawInput, INT nInput, UINT cbSizeHeader)
{
    FIXME("(paRawInput=%p, nInput=%d, cbSizeHeader=%d) stub!\n", *paRawInput, nInput, cbSizeHeader);

    return 0;
}


628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656
/**********************************************************************
 *		AttachThreadInput (USER32.@)
 *
 * Attaches the input processing mechanism of one thread to that of
 * another thread.
 */
BOOL WINAPI AttachThreadInput( DWORD from, DWORD to, BOOL attach )
{
    BOOL ret;

    SERVER_START_REQ( attach_thread_input )
    {
        req->tid_from = from;
        req->tid_to   = to;
        req->attach   = attach;
        ret = !wine_server_call_err( req );
    }
    SERVER_END_REQ;
    return ret;
}


/**********************************************************************
 *		GetKeyState (USER32.@)
 *
 * An application calls the GetKeyState function in response to a
 * keyboard-input message.  This function retrieves the state of the key
 * at the time the input message was generated.
 */
657
SHORT WINAPI DECLSPEC_HOTPATCH GetKeyState(INT vkey)
658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675
{
    SHORT retval = 0;

    SERVER_START_REQ( get_key_state )
    {
        req->tid = GetCurrentThreadId();
        req->key = vkey;
        if (!wine_server_call( req )) retval = (signed char)reply->state;
    }
    SERVER_END_REQ;
    TRACE("key (0x%x) -> %x\n", vkey, retval);
    return retval;
}


/**********************************************************************
 *		GetKeyboardState (USER32.@)
 */
676
BOOL WINAPI DECLSPEC_HOTPATCH GetKeyboardState( LPBYTE state )
677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712
{
    BOOL ret;

    TRACE("(%p)\n", state);

    memset( state, 0, 256 );
    SERVER_START_REQ( get_key_state )
    {
        req->tid = GetCurrentThreadId();
        req->key = -1;
        wine_server_set_reply( req, state, 256 );
        ret = !wine_server_call_err( req );
    }
    SERVER_END_REQ;
    return ret;
}


/**********************************************************************
 *		SetKeyboardState (USER32.@)
 */
BOOL WINAPI SetKeyboardState( LPBYTE state )
{
    BOOL ret;

    SERVER_START_REQ( set_key_state )
    {
        req->tid = GetCurrentThreadId();
        wine_server_add_data( req, state, 256 );
        ret = !wine_server_call_err( req );
    }
    SERVER_END_REQ;
    return ret;
}


713
/**********************************************************************
714
 *		VkKeyScanA (USER32.@)
715 716 717 718 719 720 721 722 723 724 725 726 727 728
 *
 * VkKeyScan translates an ANSI character to a virtual-key and shift code
 * for the current keyboard.
 * high-order byte yields :
 *	0	Unshifted
 *	1	Shift
 *	2	Ctrl
 *	3-5	Shift-key combinations that are not used for characters
 *	6	Ctrl-Alt
 *	7	Ctrl-Alt-Shift
 *	I.e. :	Shift = 1, Ctrl = 2, Alt = 4.
 * FIXME : works ok except for dead chars :
 * VkKeyScan '^'(0x5e, 94) ... got keycode 00 ... returning 00
 * VkKeyScan '`'(0x60, 96) ... got keycode 00 ... returning 00
729
 */
730
SHORT WINAPI VkKeyScanA(CHAR cChar)
731
{
732 733 734 735 736 737
    WCHAR wChar;

    if (IsDBCSLeadByte(cChar)) return -1;

    MultiByteToWideChar(CP_ACP, 0, &cChar, 1, &wChar, 1);
    return VkKeyScanW(wChar);
738 739 740
}

/******************************************************************************
741
 *		VkKeyScanW (USER32.@)
742
 */
743
SHORT WINAPI VkKeyScanW(WCHAR cChar)
744
{
745
    return VkKeyScanExW(cChar, GetKeyboardLayout(0));
746 747
}

748
/**********************************************************************
749
 *		VkKeyScanExA (USER32.@)
750 751 752
 */
WORD WINAPI VkKeyScanExA(CHAR cChar, HKL dwhkl)
{
753 754 755 756 757 758
    WCHAR wChar;

    if (IsDBCSLeadByte(cChar)) return -1;

    MultiByteToWideChar(CP_ACP, 0, &cChar, 1, &wChar, 1);
    return VkKeyScanExW(wChar, dwhkl);
759 760 761
}

/******************************************************************************
762
 *		VkKeyScanExW (USER32.@)
763 764 765
 */
WORD WINAPI VkKeyScanExW(WCHAR cChar, HKL dwhkl)
{
766
    return USER_Driver->pVkKeyScanEx(cChar, dwhkl);
767
}
768

769 770 771 772 773 774 775 776
/**********************************************************************
 *		OemKeyScan (USER32.@)
 */
DWORD WINAPI OemKeyScan(WORD wOemChar)
{
    return wOemChar;
}

777
/******************************************************************************
778
 *		GetKeyboardType (USER32.@)
779
 */
780
INT WINAPI GetKeyboardType(INT nTypeFlag)
781
{
782 783 784 785 786 787 788 789 790 791 792 793 794
    TRACE_(keyboard)("(%d)\n", nTypeFlag);
    switch(nTypeFlag)
    {
    case 0:      /* Keyboard type */
        return 4;    /* AT-101 */
    case 1:      /* Keyboard Subtype */
        return 0;    /* There are no defined subtypes */
    case 2:      /* Number of F-keys */
        return 12;   /* We're doing an 101 for now, so return 12 F-keys */
    default:
        WARN_(keyboard)("Unknown type\n");
        return 0;    /* The book says 0 here, so 0 */
    }
795 796 797
}

/******************************************************************************
798
 *		MapVirtualKeyA (USER32.@)
799
 */
800
UINT WINAPI MapVirtualKeyA(UINT code, UINT maptype)
801
{
802
    return MapVirtualKeyExA( code, maptype, GetKeyboardLayout(0) );
803 804 805
}

/******************************************************************************
806
 *		MapVirtualKeyW (USER32.@)
807
 */
808
UINT WINAPI MapVirtualKeyW(UINT code, UINT maptype)
809
{
810
    return MapVirtualKeyExW(code, maptype, GetKeyboardLayout(0));
811 812
}

813
/******************************************************************************
814
 *		MapVirtualKeyExA (USER32.@)
815
 */
816
UINT WINAPI MapVirtualKeyExA(UINT code, UINT maptype, HKL hkl)
817
{
818 819 820 821 822 823 824 825 826 827 828 829
    UINT ret;

    ret = MapVirtualKeyExW( code, maptype, hkl );
    if (maptype == MAPVK_VK_TO_CHAR)
    {
        BYTE ch = 0;
        WCHAR wch = ret;

        WideCharToMultiByte( CP_ACP, 0, &wch, 1, (LPSTR)&ch, 1, NULL, NULL );
        ret = ch;
    }
    return ret;
830 831
}

832
/******************************************************************************
833
 *		MapVirtualKeyExW (USER32.@)
834 835 836
 */
UINT WINAPI MapVirtualKeyExW(UINT code, UINT maptype, HKL hkl)
{
837
    TRACE_(keyboard)("(%X, %d, %p)\n", code, maptype, hkl);
838

839
    return USER_Driver->pMapVirtualKeyEx(code, maptype, hkl);
840 841
}

842
/****************************************************************************
843
 *		GetKBCodePage (USER32.@)
844
 */
845
UINT WINAPI GetKBCodePage(void)
846
{
847
    return GetOEMCP();
848 849
}

850
/***********************************************************************
851
 *		GetKeyboardLayout (USER32.@)
852
 *
853
 *        - device handle for keyboard layout defaulted to
854
 *          the language id. This is the way Windows default works.
855
 *        - the thread identifier is also ignored.
856
 */
857
HKL WINAPI GetKeyboardLayout(DWORD thread_id)
858
{
859
    return USER_Driver->pGetKeyboardLayout(thread_id);
860 861
}

862
/****************************************************************************
863
 *		GetKeyboardLayoutNameA (USER32.@)
864
 */
865
BOOL WINAPI GetKeyboardLayoutNameA(LPSTR pszKLID)
866
{
867 868 869 870 871
    WCHAR buf[KL_NAMELENGTH];

    if (GetKeyboardLayoutNameW(buf))
        return WideCharToMultiByte( CP_ACP, 0, buf, -1, pszKLID, KL_NAMELENGTH, NULL, NULL ) != 0;
    return FALSE;
872 873 874
}

/****************************************************************************
875
 *		GetKeyboardLayoutNameW (USER32.@)
876
 */
877
BOOL WINAPI GetKeyboardLayoutNameW(LPWSTR pwszKLID)
878
{
879
    return USER_Driver->pGetKeyboardLayoutName(pwszKLID);
880 881 882
}

/****************************************************************************
883
 *		GetKeyNameTextA (USER32.@)
884
 */
885
INT WINAPI GetKeyNameTextA(LONG lParam, LPSTR lpBuffer, INT nSize)
886
{
887 888 889
    WCHAR buf[256];
    INT ret;

890
    if (!nSize || !GetKeyNameTextW(lParam, buf, 256))
891 892
    {
        lpBuffer[0] = 0;
893
        return 0;
894
    }
895 896 897 898 899 900
    ret = WideCharToMultiByte(CP_ACP, 0, buf, -1, lpBuffer, nSize, NULL, NULL);
    if (!ret && nSize)
    {
        ret = nSize - 1;
        lpBuffer[ret] = 0;
    }
901 902
    else ret--;

903
    return ret;
904 905 906
}

/****************************************************************************
907
 *		GetKeyNameTextW (USER32.@)
908
 */
909
INT WINAPI GetKeyNameTextW(LONG lParam, LPWSTR lpBuffer, INT nSize)
910
{
911
    if (!lpBuffer || !nSize) return 0;
912
    return USER_Driver->pGetKeyNameText( lParam, lpBuffer, nSize );
913 914
}

915
/****************************************************************************
916
 *		ToUnicode (USER32.@)
917
 */
918
INT WINAPI ToUnicode(UINT virtKey, UINT scanCode, const BYTE *lpKeyState,
919 920
		     LPWSTR lpwStr, int size, UINT flags)
{
921
    return ToUnicodeEx(virtKey, scanCode, lpKeyState, lpwStr, size, flags, GetKeyboardLayout(0));
922 923 924
}

/****************************************************************************
925
 *		ToUnicodeEx (USER32.@)
926
 */
927
INT WINAPI ToUnicodeEx(UINT virtKey, UINT scanCode, const BYTE *lpKeyState,
928 929
		       LPWSTR lpwStr, int size, UINT flags, HKL hkl)
{
930
    return USER_Driver->pToUnicodeEx(virtKey, scanCode, lpKeyState, lpwStr, size, flags, hkl);
931 932
}

933
/****************************************************************************
934
 *		ToAscii (USER32.@)
935
 */
936
INT WINAPI ToAscii( UINT virtKey, UINT scanCode, const BYTE *lpKeyState,
937
                    LPWORD lpChar, UINT flags )
938
{
939
    return ToAsciiEx(virtKey, scanCode, lpKeyState, lpChar, flags, GetKeyboardLayout(0));
940 941
}

942
/****************************************************************************
943
 *		ToAsciiEx (USER32.@)
944
 */
945
INT WINAPI ToAsciiEx( UINT virtKey, UINT scanCode, const BYTE *lpKeyState,
946 947
                      LPWORD lpChar, UINT flags, HKL dwhkl )
{
948 949 950 951 952 953 954 955
    WCHAR uni_chars[2];
    INT ret, n_ret;

    ret = ToUnicodeEx(virtKey, scanCode, lpKeyState, uni_chars, 2, flags, dwhkl);
    if (ret < 0) n_ret = 1; /* FIXME: make ToUnicode return 2 for dead chars */
    else n_ret = ret;
    WideCharToMultiByte(CP_ACP, 0, uni_chars, n_ret, (LPSTR)lpChar, 2, NULL, NULL);
    return ret;
956 957
}

958
/**********************************************************************
959
 *		ActivateKeyboardLayout (USER32.@)
960
 */
961
HKL WINAPI ActivateKeyboardLayout(HKL hLayout, UINT flags)
962
{
963
    TRACE_(keyboard)("(%p, %d)\n", hLayout, flags);
964

965
    return USER_Driver->pActivateKeyboardLayout(hLayout, flags);
966 967
}

968 969 970 971 972 973 974 975 976 977
/**********************************************************************
 *		BlockInput (USER32.@)
 */
BOOL WINAPI BlockInput(BOOL fBlockIt)
{
    FIXME_(keyboard)("(%d): stub\n", fBlockIt);
    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);

    return FALSE;
}
978

979
/***********************************************************************
980
 *		GetKeyboardLayoutList (USER32.@)
981
 *
982
 * Return number of values available if either input parm is
983
 *  0, per MS documentation.
984
 */
985
UINT WINAPI GetKeyboardLayoutList(INT nBuff, HKL *layouts)
986
{
987 988 989 990 991 992 993
    HKEY hKeyKeyboard;
    DWORD rc;
    INT count = 0;
    ULONG_PTR baselayout;
    LANGID langid;
    static const WCHAR szKeyboardReg[] = {'S','y','s','t','e','m','\\','C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\','C','o','n','t','r','o','l','\\','K','e','y','b','o','a','r','d',' ','L','a','y','o','u','t','s',0};

994 995
    TRACE_(keyboard)("(%d,%p)\n",nBuff,layouts);

996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012
    baselayout = GetUserDefaultLCID();
    langid = PRIMARYLANGID(LANGIDFROMLCID(baselayout));
    if (langid == LANG_CHINESE || langid == LANG_JAPANESE || langid == LANG_KOREAN)
        baselayout |= 0xe001 << 16; /* IME */
    else
        baselayout |= baselayout << 16;

    /* Enumerate the Registry */
    rc = RegOpenKeyW(HKEY_LOCAL_MACHINE,szKeyboardReg,&hKeyKeyboard);
    if (rc == ERROR_SUCCESS)
    {
        do {
            WCHAR szKeyName[9];
            HKL layout;
            rc = RegEnumKeyW(hKeyKeyboard, count, szKeyName, 9);
            if (rc == ERROR_SUCCESS)
            {
1013
                layout = (HKL)(ULONG_PTR)strtoulW(szKeyName,NULL,16);
1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042
                if (baselayout != 0 && layout == (HKL)baselayout)
                    baselayout = 0; /* found in the registry do not add again */
                if (nBuff && layouts)
                {
                    if (count >= nBuff ) break;
                    layouts[count] = layout;
                }
                count ++;
            }
        } while (rc == ERROR_SUCCESS);
        RegCloseKey(hKeyKeyboard);
    }

    /* make sure our base layout is on the list */
    if (baselayout != 0)
    {
        if (nBuff && layouts)
        {
            if (count < nBuff)
            {
                layouts[count] = (HKL)baselayout;
                count++;
            }
        }
        else
            count++;
    }

    return count;
1043 1044 1045 1046
}


/***********************************************************************
1047
 *		RegisterHotKey (USER32.@)
1048
 */
1049 1050
BOOL WINAPI RegisterHotKey(HWND hwnd,INT id,UINT modifiers,UINT vk)
{
1051
    BOOL ret;
1052
    int replaced=0;
1053 1054 1055

    TRACE_(keyboard)("(%p,%d,0x%08x,%X)\n",hwnd,id,modifiers,vk);

1056 1057 1058
    if ((hwnd == NULL || WIN_IsCurrentThread(hwnd)) &&
        !USER_Driver->pRegisterHotKey(hwnd, modifiers, vk))
        return FALSE;
1059 1060 1061 1062 1063 1064 1065

    SERVER_START_REQ( register_hotkey )
    {
        req->window = wine_server_user_handle( hwnd );
        req->id = id;
        req->flags = modifiers;
        req->vkey = vk;
1066 1067 1068 1069 1070 1071
        if ((ret = !wine_server_call_err( req )))
        {
            replaced = reply->replaced;
            modifiers = reply->flags;
            vk = reply->vkey;
        }
1072 1073 1074
    }
    SERVER_END_REQ;

1075 1076
    if (ret && replaced)
        USER_Driver->pUnregisterHotKey(hwnd, modifiers, vk);
1077 1078

    return ret;
1079 1080 1081
}

/***********************************************************************
1082
 *		UnregisterHotKey (USER32.@)
1083
 */
1084 1085
BOOL WINAPI UnregisterHotKey(HWND hwnd,INT id)
{
1086
    BOOL ret;
1087
    UINT modifiers, vk;
1088 1089 1090 1091 1092 1093 1094

    TRACE_(keyboard)("(%p,%d)\n",hwnd,id);

    SERVER_START_REQ( unregister_hotkey )
    {
        req->window = wine_server_user_handle( hwnd );
        req->id = id;
1095 1096 1097 1098 1099
        if ((ret = !wine_server_call_err( req )))
        {
            modifiers = reply->flags;
            vk = reply->vkey;
        }
1100 1101 1102
    }
    SERVER_END_REQ;

1103 1104
    if (ret)
        USER_Driver->pUnregisterHotKey(hwnd, modifiers, vk);
1105 1106

    return ret;
1107 1108
}

1109
/***********************************************************************
1110
 *		LoadKeyboardLayoutW (USER32.@)
1111
 */
1112
HKL WINAPI LoadKeyboardLayoutW(LPCWSTR pwszKLID, UINT Flags)
1113
{
1114
    TRACE_(keyboard)("(%s, %d)\n", debugstr_w(pwszKLID), Flags);
1115

1116
    return USER_Driver->pLoadKeyboardLayout(pwszKLID, Flags);
1117 1118 1119
}

/***********************************************************************
1120
 *		LoadKeyboardLayoutA (USER32.@)
1121
 */
1122
HKL WINAPI LoadKeyboardLayoutA(LPCSTR pwszKLID, UINT Flags)
1123
{
1124 1125
    HKL ret;
    UNICODE_STRING pwszKLIDW;
1126

1127 1128 1129 1130 1131 1132
    if (pwszKLID) RtlCreateUnicodeStringFromAsciiz(&pwszKLIDW, pwszKLID);
    else pwszKLIDW.Buffer = NULL;

    ret = LoadKeyboardLayoutW(pwszKLIDW.Buffer, Flags);
    RtlFreeUnicodeString(&pwszKLIDW);
    return ret;
1133
}
1134 1135


1136 1137 1138 1139 1140 1141 1142
/***********************************************************************
 *		UnloadKeyboardLayout (USER32.@)
 */
BOOL WINAPI UnloadKeyboardLayout(HKL hkl)
{
    TRACE_(keyboard)("(%p)\n", hkl);

1143
    return USER_Driver->pUnloadKeyboardLayout(hkl);
1144 1145
}

1146 1147 1148
typedef struct __TRACKINGLIST {
    TRACKMOUSEEVENT tme;
    POINT pos; /* center of hover rectangle */
1149
} _TRACKINGLIST;
1150

1151 1152
/* FIXME: move tracking stuff into a per thread data */
static _TRACKINGLIST tracking_info;
1153 1154
static UINT_PTR timer;

1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189
static void check_mouse_leave(HWND hwnd, int hittest)
{
    if (tracking_info.tme.hwndTrack != hwnd)
    {
        if (tracking_info.tme.dwFlags & TME_NONCLIENT)
            PostMessageW(tracking_info.tme.hwndTrack, WM_NCMOUSELEAVE, 0, 0);
        else
            PostMessageW(tracking_info.tme.hwndTrack, WM_MOUSELEAVE, 0, 0);

        /* remove the TME_LEAVE flag */
        tracking_info.tme.dwFlags &= ~TME_LEAVE;
    }
    else
    {
        if (hittest == HTCLIENT)
        {
            if (tracking_info.tme.dwFlags & TME_NONCLIENT)
            {
                PostMessageW(tracking_info.tme.hwndTrack, WM_NCMOUSELEAVE, 0, 0);
                /* remove the TME_LEAVE flag */
                tracking_info.tme.dwFlags &= ~TME_LEAVE;
            }
        }
        else
        {
            if (!(tracking_info.tme.dwFlags & TME_NONCLIENT))
            {
                PostMessageW(tracking_info.tme.hwndTrack, WM_MOUSELEAVE, 0, 0);
                /* remove the TME_LEAVE flag */
                tracking_info.tme.dwFlags &= ~TME_LEAVE;
            }
        }
    }
}

1190 1191
static void CALLBACK TrackMouseEventProc(HWND hwnd, UINT uMsg, UINT_PTR idEvent,
                                         DWORD dwTime)
1192 1193
{
    POINT pos;
1194 1195
    INT hoverwidth = 0, hoverheight = 0, hittest;

1196
    TRACE("hwnd %p, msg %04x, id %04lx, time %u\n", hwnd, uMsg, idEvent, dwTime);
1197 1198

    GetCursorPos(&pos);
1199 1200 1201
    hwnd = WINPOS_WindowFromPoint(hwnd, pos, &hittest);

    TRACE("point %s hwnd %p hittest %d\n", wine_dbgstr_point(&pos), hwnd, hittest);
1202

1203 1204
    SystemParametersInfoW(SPI_GETMOUSEHOVERWIDTH, 0, &hoverwidth, 0);
    SystemParametersInfoW(SPI_GETMOUSEHOVERHEIGHT, 0, &hoverheight, 0);
1205

1206 1207 1208 1209
    TRACE("tracked pos %s, current pos %s, hover width %d, hover height %d\n",
           wine_dbgstr_point(&tracking_info.pos), wine_dbgstr_point(&pos),
           hoverwidth, hoverheight);

1210 1211 1212 1213
    /* see if this tracking event is looking for TME_LEAVE and that the */
    /* mouse has left the window */
    if (tracking_info.tme.dwFlags & TME_LEAVE)
    {
1214
        check_mouse_leave(hwnd, hittest);
1215
    }
1216

1217 1218 1219 1220 1221 1222
    if (tracking_info.tme.hwndTrack != hwnd)
    {
        /* mouse is gone, stop tracking mouse hover */
        tracking_info.tme.dwFlags &= ~TME_HOVER;
    }

1223 1224 1225 1226
    /* see if we are tracking hovering for this hwnd */
    if (tracking_info.tme.dwFlags & TME_HOVER)
    {
        /* has the cursor moved outside the rectangle centered around pos? */
1227 1228
        if ((abs(pos.x - tracking_info.pos.x) > (hoverwidth / 2)) ||
            (abs(pos.y - tracking_info.pos.y) > (hoverheight / 2)))
1229
        {
1230
            /* record this new position as the current position */
1231 1232 1233 1234
            tracking_info.pos = pos;
        }
        else
        {
1235 1236 1237 1238
            if (hittest == HTCLIENT)
            {
                ScreenToClient(hwnd, &pos);
                TRACE("client cursor pos %s\n", wine_dbgstr_point(&pos));
1239 1240

                PostMessageW(tracking_info.tme.hwndTrack, WM_MOUSEHOVER,
1241 1242 1243 1244 1245 1246 1247 1248
                             get_key_state(), MAKELPARAM( pos.x, pos.y ));
            }
            else
            {
                if (tracking_info.tme.dwFlags & TME_NONCLIENT)
                    PostMessageW(tracking_info.tme.hwndTrack, WM_NCMOUSEHOVER,
                                 hittest, MAKELPARAM( pos.x, pos.y ));
            }
1249 1250 1251

            /* stop tracking mouse hover */
            tracking_info.tme.dwFlags &= ~TME_HOVER;
1252 1253
        }
    }
1254

1255
    /* stop the timer if the tracking list is empty */
1256 1257
    if (!(tracking_info.tme.dwFlags & (TME_HOVER | TME_LEAVE)))
    {
1258
        KillSystemTimer(tracking_info.tme.hwndTrack, timer);
1259
        timer = 0;
1260 1261 1262
        tracking_info.tme.hwndTrack = 0;
        tracking_info.tme.dwFlags = 0;
        tracking_info.tme.dwHoverTime = 0;
1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293
    }
}


/***********************************************************************
 * TrackMouseEvent [USER32]
 *
 * Requests notification of mouse events
 *
 * During mouse tracking WM_MOUSEHOVER or WM_MOUSELEAVE events are posted
 * to the hwnd specified in the ptme structure.  After the event message
 * is posted to the hwnd, the entry in the queue is removed.
 *
 * If the current hwnd isn't ptme->hwndTrack the TME_HOVER flag is completely
 * ignored. The TME_LEAVE flag results in a WM_MOUSELEAVE message being posted
 * immediately and the TME_LEAVE flag being ignored.
 *
 * PARAMS
 *     ptme [I,O] pointer to TRACKMOUSEEVENT information structure.
 *
 * RETURNS
 *     Success: non-zero
 *     Failure: zero
 *
 */

BOOL WINAPI
TrackMouseEvent (TRACKMOUSEEVENT *ptme)
{
    HWND hwnd;
    POINT pos;
1294
    DWORD hover_time;
1295
    INT hittest;
1296

1297
    TRACE("%x, %x, %p, %u\n", ptme->cbSize, ptme->dwFlags, ptme->hwndTrack, ptme->dwHoverTime);
1298 1299 1300

    if (ptme->cbSize != sizeof(TRACKMOUSEEVENT)) {
        WARN("wrong TRACKMOUSEEVENT size from app\n");
1301
        SetLastError(ERROR_INVALID_PARAMETER);
1302 1303 1304
        return FALSE;
    }

1305 1306 1307 1308
    /* fill the TRACKMOUSEEVENT struct with the current tracking for the given hwnd */
    if (ptme->dwFlags & TME_QUERY )
    {
        *ptme = tracking_info.tme;
1309 1310
        /* set cbSize in the case it's not initialized yet */
        ptme->cbSize = sizeof(TRACKMOUSEEVENT);
1311

1312
        return TRUE; /* return here, TME_QUERY is retrieving information */
1313 1314
    }

1315 1316 1317 1318
    if (!IsWindow(ptme->hwndTrack))
    {
        SetLastError(ERROR_INVALID_WINDOW_HANDLE);
        return FALSE;
1319 1320
    }

1321
    hover_time = (ptme->dwFlags & TME_HOVER) ? ptme->dwHoverTime : HOVER_DEFAULT;
1322

1323
    /* if HOVER_DEFAULT was specified replace this with the system's current value.
1324
     * TME_LEAVE doesn't need to specify hover time so use default */
1325
    if (hover_time == HOVER_DEFAULT || hover_time == 0)
1326
        SystemParametersInfoW(SPI_GETMOUSEHOVERTIME, 0, &hover_time, 0);
1327

1328
    GetCursorPos(&pos);
1329 1330
    hwnd = WINPOS_WindowFromPoint(ptme->hwndTrack, pos, &hittest);
    TRACE("point %s hwnd %p hittest %d\n", wine_dbgstr_point(&pos), hwnd, hittest);
1331

1332
    if (ptme->dwFlags & ~(TME_CANCEL | TME_HOVER | TME_LEAVE | TME_NONCLIENT))
1333
        FIXME("Unknown flag(s) %08x\n", ptme->dwFlags & ~(TME_CANCEL | TME_HOVER | TME_LEAVE | TME_NONCLIENT));
1334

1335 1336 1337 1338 1339
    if (ptme->dwFlags & TME_CANCEL)
    {
        if (tracking_info.tme.hwndTrack == ptme->hwndTrack)
        {
            tracking_info.tme.dwFlags &= ~(ptme->dwFlags & ~TME_CANCEL);
1340 1341

            /* if we aren't tracking on hover or leave remove this entry */
1342
            if (!(tracking_info.tme.dwFlags & (TME_HOVER | TME_LEAVE)))
1343
            {
1344
                KillSystemTimer(tracking_info.tme.hwndTrack, timer);
1345
                timer = 0;
1346 1347 1348
                tracking_info.tme.hwndTrack = 0;
                tracking_info.tme.dwFlags = 0;
                tracking_info.tme.dwHoverTime = 0;
1349 1350 1351
            }
        }
    } else {
1352 1353 1354 1355 1356 1357
        /* In our implementation it's possible that another window will receive a
         * WM_MOUSEMOVE and call TrackMouseEvent before TrackMouseEventProc is
         * called. In such a situation post the WM_MOUSELEAVE now */
        if (tracking_info.tme.dwFlags & TME_LEAVE && tracking_info.tme.hwndTrack != NULL)
            check_mouse_leave(hwnd, hittest);

1358 1359 1360 1361 1362 1363 1364 1365 1366
        if (timer)
        {
            KillSystemTimer(tracking_info.tme.hwndTrack, timer);
            timer = 0;
            tracking_info.tme.hwndTrack = 0;
            tracking_info.tme.dwFlags = 0;
            tracking_info.tme.dwHoverTime = 0;
        }

1367 1368
        if (ptme->hwndTrack == hwnd)
        {
1369
            /* Adding new mouse event to the tracking list */
1370 1371
            tracking_info.tme = *ptme;
            tracking_info.tme.dwHoverTime = hover_time;
1372 1373

            /* Initialize HoverInfo variables even if not hover tracking */
1374
            tracking_info.pos = pos;
1375

1376
            timer = SetSystemTimer(tracking_info.tme.hwndTrack, (UINT_PTR)&tracking_info.tme, hover_time, TrackMouseEventProc);
1377 1378 1379 1380 1381
        }
    }

    return TRUE;
}
1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396

/***********************************************************************
 * GetMouseMovePointsEx [USER32]
 *
 * RETURNS
 *     Success: count of point set in the buffer
 *     Failure: -1
 */
int WINAPI GetMouseMovePointsEx(UINT size, LPMOUSEMOVEPOINT ptin, LPMOUSEMOVEPOINT ptout, int count, DWORD res) {

    if((size != sizeof(MOUSEMOVEPOINT)) || (count < 0) || (count > 64)) {
        SetLastError(ERROR_INVALID_PARAMETER);
        return -1;
    }

1397
    if(!ptin || (!ptout && count)) {
1398 1399 1400 1401 1402 1403 1404 1405 1406
        SetLastError(ERROR_NOACCESS);
        return -1;
    }

    FIXME("(%d %p %p %d %d) stub\n", size, ptin, ptout, count, res);

    SetLastError(ERROR_POINT_NOT_FOUND);
    return -1;
}