source: trunk/src/user32/winmouse.cpp@ 8702

Last change on this file since 8702 was 8702, checked in by sandervl, 23 years ago

minor logging changes

File size: 19.7 KB
Line 
1/* $Id: winmouse.cpp,v 1.25 2002-06-18 09:32:26 sandervl Exp $ */
2/*
3 * Win32 mouse functions
4 *
5 * Copyright 1999-2002 Sander van Leeuwen
6 *
7 * Parts based on Wine code (windows\input.c) (TrackMouseEvent)
8 *
9 * Copyright 1993 Bob Amstadt
10 * Copyright 1996 Albrecht Kleine
11 * Copyright 1997 David Faure
12 * Copyright 1998 Morten Welinder
13 * Copyright 1998 Ulrich Weigand
14 *
15 * TODO: SwapMouseButton:
16 * We shouldn't let win32 apps change this for the whole system
17 * better to change mouse button message translation instead
18 *
19 * Project Odin Software License can be found in LICENSE.TXT
20 *
21 */
22
23#include <odin.h>
24#include <odinwrap.h>
25#include <os2sel.h>
26
27#include <os2win.h>
28#include <misc.h>
29#include "win32wbase.h"
30#include <winuser32.h>
31#include <winuser.h>
32#include <commctrl.h>
33#include <debugtools.h>
34#include <win\mouse.h>
35#include "winmouse.h"
36#include "oslibmsg.h"
37#include "oslibres.h"
38#include "pmwindow.h"
39#include "oslibwin.h"
40#include "hook.h"
41
42#define DBG_LOCALLOG DBG_winmouse
43#include "dbglocal.h"
44
45
46ODINDEBUGCHANNEL(USER32-WINMOUSE)
47
48
49/****************************************************************************
50 * local variables
51 ****************************************************************************/
52
53//******************************************************************************
54//******************************************************************************
55BOOL WIN32API GetCursorPos( PPOINT lpPoint)
56{
57 if (!lpPoint) return FALSE;
58
59 if (OSLibWinQueryPointerPos(lpPoint)) //POINT == POINTL
60 {
61 mapScreenPoint((OSLIBPOINT*)lpPoint);
62 dprintf2(("USER32: GetCursorPos (%d,%d)", lpPoint->x, lpPoint->y));
63 return TRUE;
64 }
65 else return FALSE;
66}
67//******************************************************************************
68//******************************************************************************
69BOOL WIN32API SetCursorPos( int X, int Y)
70{
71 BOOL ret;
72 dprintf(("USER32: SetCursorPos (%d,%d)", X,Y));
73
74 ret = OSLibWinSetPointerPos(X, mapScreenY(Y));
75 if(ret == TRUE) {
76 MSLLHOOKSTRUCT hook;
77
78 hook.pt.x = X;
79 hook.pt.y = Y;
80 hook.mouseData = 0;
81 //signal to dinput hook that it only needs to modify the last
82 //known position (not treat it as a new event)
83 hook.flags = LLMHF_INJECTED;
84 hook.time = GetCurrentTime();
85 hook.dwExtraInfo = 0;
86
87 HOOK_CallHooksW( WH_MOUSE_LL, HC_ACTION, WM_MOUSEMOVE, (LPARAM)&hook);
88 }
89 return ret;
90}
91//******************************************************************************
92//******************************************************************************
93BOOL WIN32API ClipCursor(const RECT * lpRect)
94{
95 if(lpRect) {
96 dprintf(("USER32: ClipCursor (%d,%d)(%d,%d)", lpRect->left, lpRect->top, lpRect->right, lpRect->bottom));
97 }
98 else dprintf(("USER32: ClipCursor NULL"));
99 return OSLibWinClipCursor(lpRect);
100}
101//******************************************************************************
102//******************************************************************************
103BOOL WIN32API GetClipCursor( LPRECT lpRect)
104{
105 dprintf(("USER32: GetClipCursor %x", lpRect));
106 return OSLibWinGetClipCursor(lpRect);
107}
108//******************************************************************************
109// capture handle "cache"
110static HWND hwndWin32Capture = 0;
111//******************************************************************************
112HWND WIN32API GetCapture()
113{
114 if (0 == hwndWin32Capture)
115 hwndWin32Capture = OS2ToWin32Handle(OSLibWinQueryCapture());
116
117 return hwndWin32Capture;
118}
119//******************************************************************************
120//******************************************************************************
121HWND WIN32API SetCapture(HWND hwnd)
122{
123 HWND hwndPrev = GetCapture();
124 BOOL rc;
125
126 // invalidate capture "cache"
127 hwndWin32Capture = 0;
128
129 if(hwnd == 0)
130 {
131 ReleaseCapture();
132 return hwndPrev;
133 }
134
135 if(hwnd == hwndPrev)
136 {
137 dprintf(("USER32: SetCapture %x; already set to that window; ignore", hwnd));
138 return hwndPrev;
139 }
140
141 if(hwndPrev != NULL)
142 {
143 //SvL: WinSetCapture returns an error if mouse is already captured
144 OSLibWinSetCapture(0);
145 }
146
147 rc = OSLibWinSetCapture(Win32ToOS2Handle(hwnd));
148 dprintf(("USER32: SetCapture %x (prev %x) returned %d", hwnd, hwndPrev, rc));
149 if(hwndPrev)
150 {
151 SendMessageA(hwndPrev, WM_CAPTURECHANGED, 0L, hwnd);
152 }
153 return hwndPrev;
154}
155//******************************************************************************
156//******************************************************************************
157BOOL WIN32API ReleaseCapture()
158{
159 HWND hwndPrev;
160 BOOL ret;
161
162 hwndPrev = GetCapture();
163
164 // invalidate capture "cache"
165 hwndWin32Capture = 0;
166
167 ret = OSLibWinSetCapture(0);
168 if(hwndPrev)
169 {
170 SendMessageA(hwndPrev, WM_CAPTURECHANGED, 0L, 0L);
171 }
172 return ret;
173}
174//******************************************************************************
175//******************************************************************************
176UINT WIN32API GetDoubleClickTime()
177{
178 UINT result = OSLibWinQuerySysValue(SVOS_DBLCLKTIME);
179 if(result == 0)
180 SetLastError(ERROR_INVALID_PARAMETER); //TODO: ????
181
182 return result;
183}
184//******************************************************************************
185//******************************************************************************
186BOOL WIN32API SetDoubleClickTime(UINT uInterval)
187{
188 BOOL ret = TRUE;
189
190 ret = OSLibWinSetSysValue(SVOS_DBLCLKTIME, uInterval);
191 if(ret == FALSE )
192 {
193 SetLastError(ERROR_INVALID_PARAMETER); //TODO: ????
194 }
195 return (ret);
196}
197//******************************************************************************
198//TODO: we shouldn't let win32 apps change this for the whole system
199// better to change mouse button message translation instead
200BOOL OPEN32API __SwapMouseButton(BOOL swapFlag);
201
202inline BOOL _SwapMouseButton(BOOL swapFlag)
203{
204 BOOL yyrc;
205 USHORT sel = RestoreOS2FS();
206
207 yyrc = __SwapMouseButton(swapFlag);
208 SetFS(sel);
209
210 return yyrc;
211}
212
213//******************************************************************************
214BOOL WIN32API SwapMouseButton(BOOL fSwap)
215{
216 return _SwapMouseButton(fSwap);
217}
218
219/*****************************************************************************
220 * Name : VOID WIN32API mouse_event
221 * Purpose : The mouse_event function synthesizes mouse motion and button clicks.
222 * Parameters: DWORD dwFlags flags specifying various motion/click variants
223 * DWORD dx horizontal mouse position or position change
224 * DWORD dy vertical mouse position or position change
225 * DWORD cButtons unused, reserved for future use, set to zero
226 * DWORD dwExtraInfo 32 bits of application-defined information
227 * Variables :
228 * Result :
229 * Remark :
230 * Status : UNTESTED STUB
231 *
232 * Author : Patrick Haller [Thu, 1998/02/26 11:55]
233 *****************************************************************************/
234
235VOID WIN32API mouse_event(DWORD dwFlags, DWORD dx, DWORD dy, DWORD cButtons,
236 DWORD dwExtraInfo)
237{
238 INPUT i;
239
240 // format input packet
241 i.type = INPUT_MOUSE;
242 i.mi.dx = dx;
243 i.mi.dy = dy;
244 i.mi.mouseData = cButtons; // PH: is this really correct?
245 i.mi.dwFlags = dwFlags;
246 i.mi.dwExtraInfo = dwExtraInfo;
247
248 // forward to more modern API
249 SendInput(1, &i, sizeof(i) );
250}
251
252
253/*****************************************************************************
254 * Name : UINT SendInput
255 * Purpose : The SendInput function synthesizes keystrokes, mouse motions,
256 * and button clicks
257 * Parameters: UINT nInputs // count if input events
258 * LPINPUT pInputs // array of input structures
259 * int chSize // size of structure
260 * Variables :
261 * Result : number of events successfully inserted,
262 * 0 if the input was already blocked by another thread
263 * Remark :
264 * Status : UNTESTED STUB
265 * TODO: call hooks!!
266 *
267 * Author : Patrick Haller [Thu, 1998/02/26 11:55]
268 *****************************************************************************/
269
270UINT WIN32API SendInput(UINT nInputs, LPINPUT pInputs, int chSize)
271{
272 dprintf(("not correctly implemented"));
273
274 // The simulated input is sent to the
275 // foreground thread's message queue.
276 // (WM_KEYUP, WM_KEYDOWN)
277 // After GetMessage or PeekMessage,
278 // TranslateMessage posts an appropriate
279 // WM_CHAR message.
280 HWND hwnd = GetForegroundWindow();
281
282 LPINPUT piBase = pInputs;
283 for (int i = 0;
284 i < nInputs;
285 i++,
286 piBase++)
287 {
288 switch(piBase->type)
289 {
290 case INPUT_MOUSE:
291 {
292 PMOUSEINPUT p = (PMOUSEINPUT)&piBase->mi;
293 MSG msg;
294
295 // simulate mouse input message
296 // @@@PH
297 }
298 break;
299
300 // compose a keyboard input message
301 case INPUT_KEYBOARD:
302 {
303 PKEYBDINPUT p = (PKEYBDINPUT)&piBase->ki;
304 MSG msg;
305 BOOL fUnicode = (p->dwFlags & KEYEVENTF_UNICODE) == KEYEVENTF_UNICODE;
306 DWORD extrainfo = GetMessageExtraInfo();
307
308 // build keyboard message
309 msg.message = (p->dwFlags & KEYEVENTF_KEYUP) ? WM_KEYUP : WM_KEYDOWN;
310
311 if (p->dwFlags & KEYEVENTF_SCANCODE)
312 {
313 // keystroke is identified by the scancode
314 if (fUnicode)
315 msg.wParam = MapVirtualKeyW(p->wScan, 1);
316 else
317 msg.wParam = MapVirtualKeyA(p->wScan, 1);
318 }
319 else
320 msg.wParam = p->wVk;
321
322 msg.lParam = 0x0000001 | // repeat count
323 ( (p->wScan & 0xff) << 16); // scan code
324
325 if (p->dwFlags & KEYEVENTF_EXTENDEDKEY)
326 msg.lParam |= (1 << 24);
327
328 // set additional message flags
329 if (msg.message == WM_KEYDOWN)
330 {
331 // @@@PH
332 // bit 30 - previous key state cannot be set, how to determine?
333 }
334 else
335 {
336 // WM_KEYUP -> previous key is always 1, transistion state
337 // always 1
338 msg.lParam |= (1 << 30);
339 msg.lParam |= (1 << 31);
340 }
341
342 msg.time = p->time;
343
344 // @@@PH
345 // unknown: do we have to post or to send the message?
346
347 SetMessageExtraInfo( (LPARAM)p->dwExtraInfo );
348
349 if (fUnicode)
350 SendMessageW(hwnd, msg.message, msg.wParam, msg.lParam);
351 else
352 SendMessageA(hwnd, msg.message, msg.wParam, msg.lParam);
353
354 //restore extra info
355 SetMessageExtraInfo(extrainfo);
356 break;
357 }
358
359 case INPUT_HARDWARE:
360 {
361 PHARDWAREINPUT p = (PHARDWAREINPUT)&piBase->hi;
362
363 // @@@PH
364 // not supported for the time being
365 }
366 break;
367
368 default:
369 dprintf(("unsupported input packet type %d",
370 piBase->type));
371 break;
372 }
373 }
374
375 return 0;
376}
377
378/*****************************************************************************
379 * Name : BOOL WIN32API DragDetect
380 * Purpose : The DragDetect function captures the mouse and tracks its movement
381 * Parameters: HWND hwnd
382 * POINT pt
383 * Variables :
384 * Result : If the user moved the mouse outside of the drag rectangle while
385 * holding the left button down, the return value is TRUE.
386 * If the user did not move the mouse outside of the drag rectangle
387 * while holding the left button down, the return value is FALSE.
388 * Remark :
389 * Status : UNTESTED STUB
390 *
391 * Author : Patrick Haller [Thu, 1998/02/26 11:55]
392 *****************************************************************************/
393BOOL WIN32API DragDetect(HWND hwnd, POINT pt)
394{
395 dprintf(("not implemented"));
396
397 return (FALSE);
398}
399//******************************************************************************
400//******************************************************************************
401typedef struct __TRACKINGLIST {
402 TRACKMOUSEEVENT tme;
403 POINT pos; /* center of hover rectangle */
404 INT iHoverTime; /* elapsed time the cursor has been inside of the hover rect */
405} _TRACKINGLIST;
406
407#define UINT_PTR UINT
408static _TRACKINGLIST TrackingList[10];
409static int iTrackMax = 0;
410static UINT_PTR timer;
411static const INT iTimerInterval = 50; /* msec for timer interval */
412
413/* FIXME: need to implement WM_NCMOUSELEAVE and WM_NCMOUSEHOVER for */
414/* TrackMouseEventProc and _TrackMouseEvent */
415static void CALLBACK TrackMouseEventProc(HWND hwndUnused, UINT uMsg, UINT_PTR idEvent,
416 DWORD dwTime)
417{
418 int i = 0;
419 POINT pos;
420 HWND hwnd;
421 INT hoverwidth = 0, hoverheight = 0;
422
423 GetCursorPos(&pos);
424 hwnd = WindowFromPoint(pos);
425
426 SystemParametersInfoA(SPI_GETMOUSEHOVERWIDTH, 0, &hoverwidth, 0);
427 SystemParametersInfoA(SPI_GETMOUSEHOVERHEIGHT, 0, &hoverheight, 0);
428
429 /* loop through tracking events we are processing */
430 while (i < iTrackMax) {
431 /* see if this tracking event is looking for TME_LEAVE and that the */
432 /* mouse has left the window */
433 if ((TrackingList[i].tme.dwFlags & TME_LEAVE) &&
434 (TrackingList[i].tme.hwndTrack != hwnd)) {
435 PostMessageA(TrackingList[i].tme.hwndTrack, WM_MOUSELEAVE, 0, 0);
436
437 /* remove the TME_LEAVE flag */
438 TrackingList[i].tme.dwFlags ^= TME_LEAVE;
439 }
440
441 /* see if we are tracking hovering for this hwnd */
442 if(TrackingList[i].tme.dwFlags & TME_HOVER) {
443 /* add the timer interval to the hovering time */
444 TrackingList[i].iHoverTime+=iTimerInterval;
445
446 /* has the cursor moved outside the rectangle centered around pos? */
447 if((abs(pos.x - TrackingList[i].pos.x) > (hoverwidth / 2.0))
448 || (abs(pos.y - TrackingList[i].pos.y) > (hoverheight / 2.0)))
449 {
450 /* record this new position as the current position and reset */
451 /* the iHoverTime variable to 0 */
452 TrackingList[i].pos = pos;
453 TrackingList[i].iHoverTime = 0;
454 }
455
456 /* has the mouse hovered long enough? */
457 if(TrackingList[i].iHoverTime <= TrackingList[i].tme.dwHoverTime)
458 {
459 PostMessageA(TrackingList[i].tme.hwndTrack, WM_MOUSEHOVER, 0, 0);
460
461 /* stop tracking mouse hover */
462 TrackingList[i].tme.dwFlags ^= TME_HOVER;
463 }
464 }
465
466 /* see if we are still tracking TME_HOVER or TME_LEAVE for this entry */
467 if((TrackingList[i].tme.dwFlags & TME_HOVER) ||
468 (TrackingList[i].tme.dwFlags & TME_LEAVE)) {
469 i++;
470 } else { /* remove this entry from the tracking list */
471 TrackingList[i] = TrackingList[--iTrackMax];
472 }
473 }
474
475 /* stop the timer if the tracking list is empty */
476 if(iTrackMax == 0) {
477 KillTimer(0, timer);
478 timer = 0;
479 }
480}
481
482
483/***********************************************************************
484 * TrackMouseEvent [USER32]
485 *
486 * Requests notification of mouse events
487 *
488 * During mouse tracking WM_MOUSEHOVER or WM_MOUSELEAVE events are posted
489 * to the hwnd specified in the ptme structure. After the event message
490 * is posted to the hwnd, the entry in the queue is removed.
491 *
492 * If the current hwnd isn't ptme->hwndTrack the TME_HOVER flag is completely
493 * ignored. The TME_LEAVE flag results in a WM_MOUSELEAVE message being posted
494 * immediately and the TME_LEAVE flag being ignored.
495 *
496 * PARAMS
497 * ptme [I,O] pointer to TRACKMOUSEEVENT information structure.
498 *
499 * RETURNS
500 * Success: non-zero
501 * Failure: zero
502 *
503 */
504
505BOOL WINAPI
506TrackMouseEvent (TRACKMOUSEEVENT *ptme)
507{
508 DWORD flags = 0;
509 int i = 0;
510 BOOL cancel = 0, hover = 0, leave = 0, query = 0;
511 HWND hwnd;
512 POINT pos;
513
514 pos.x = 0;
515 pos.y = 0;
516
517 dprintf(("TrackMouseEvent: %lx, %lx, %x, %lx\n", ptme->cbSize, ptme->dwFlags, ptme->hwndTrack, ptme->dwHoverTime));
518
519 if (ptme->cbSize != sizeof(TRACKMOUSEEVENT)) {
520 WARN("wrong TRACKMOUSEEVENT size from app\n");
521 SetLastError(ERROR_INVALID_PARAMETER); /* FIXME not sure if this is correct */
522 return FALSE;
523 }
524
525 flags = ptme->dwFlags;
526
527 /* if HOVER_DEFAULT was specified replace this with the systems current value */
528 if(ptme->dwHoverTime == HOVER_DEFAULT)
529 SystemParametersInfoA(SPI_GETMOUSEHOVERTIME, 0, &(ptme->dwHoverTime), 0);
530
531 GetCursorPos(&pos);
532 hwnd = WindowFromPoint(pos);
533
534 if ( flags & TME_CANCEL ) {
535 flags &= ~ TME_CANCEL;
536 cancel = 1;
537 }
538
539 if ( flags & TME_HOVER ) {
540 flags &= ~ TME_HOVER;
541 hover = 1;
542 }
543
544 if ( flags & TME_LEAVE ) {
545 flags &= ~ TME_LEAVE;
546 leave = 1;
547 }
548
549 /* fill the TRACKMOUSEEVENT struct with the current tracking for the given hwnd */
550 if ( flags & TME_QUERY ) {
551 flags &= ~ TME_QUERY;
552 query = 1;
553 i = 0;
554
555 /* Find the tracking list entry with the matching hwnd */
556 while((i < iTrackMax) && (TrackingList[i].tme.hwndTrack != ptme->hwndTrack)) {
557 i++;
558 }
559
560 /* hwnd found, fill in the ptme struct */
561 if(i < iTrackMax)
562 *ptme = TrackingList[i].tme;
563 else
564 ptme->dwFlags = 0;
565
566 return TRUE; /* return here, TME_QUERY is retrieving information */
567 }
568
569 if ( flags )
570 FIXME("Unknown flag(s) %08lx\n", flags );
571
572 if(cancel) {
573 /* find a matching hwnd if one exists */
574 i = 0;
575
576 while((i < iTrackMax) && (TrackingList[i].tme.hwndTrack != ptme->hwndTrack)) {
577 i++;
578 }
579
580 if(i < iTrackMax) {
581 TrackingList[i].tme.dwFlags &= ~(ptme->dwFlags & ~TME_CANCEL);
582
583 /* if we aren't tracking on hover or leave remove this entry */
584 if(!((TrackingList[i].tme.dwFlags & TME_HOVER) ||
585 (TrackingList[i].tme.dwFlags & TME_LEAVE)))
586 {
587 TrackingList[i] = TrackingList[--iTrackMax];
588
589 if(iTrackMax == 0) {
590 KillTimer(0, timer);
591 timer = 0;
592 }
593 }
594 }
595 } else {
596 /* see if hwndTrack isn't the current window */
597 if(ptme->hwndTrack != hwnd) {
598 if(leave) {
599 PostMessageA(ptme->hwndTrack, WM_MOUSELEAVE, 0, 0);
600 }
601 } else {
602 /* See if this hwnd is already being tracked and update the tracking flags */
603 for(i = 0; i < iTrackMax; i++) {
604 if(TrackingList[i].tme.hwndTrack == ptme->hwndTrack) {
605 if(hover) {
606 TrackingList[i].tme.dwFlags |= TME_HOVER;
607 TrackingList[i].tme.dwHoverTime = ptme->dwHoverTime;
608 }
609
610 if(leave)
611 TrackingList[i].tme.dwFlags |= TME_LEAVE;
612
613 /* reset iHoverTime as per winapi specs */
614 TrackingList[i].iHoverTime = 0;
615
616 return TRUE;
617 }
618 }
619
620 /* if the tracking list is full return FALSE */
621 if (iTrackMax == sizeof (TrackingList) / sizeof(*TrackingList)) {
622 return FALSE;
623 }
624
625 /* Adding new mouse event to the tracking list */
626 TrackingList[iTrackMax].tme = *ptme;
627
628 /* Initialize HoverInfo variables even if not hover tracking */
629 TrackingList[iTrackMax].iHoverTime = 0;
630 TrackingList[iTrackMax].pos = pos;
631
632 iTrackMax++;
633
634 if (!timer) {
635 timer = SetTimer(0, 0, iTimerInterval, (TIMERPROC)TrackMouseEventProc);
636 }
637 }
638 }
639
640 return TRUE;
641}
642//******************************************************************************
643//******************************************************************************
Note: See TracBrowser for help on using the repository browser.