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

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

Implemented WH_MOUSE_LL hook; removed DInput hack for keyboard & mouse message translation

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