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

Last change on this file since 8266 was 7875, checked in by sandervl, 24 years ago

logging updates

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