News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests
NB: Posting URL's See here: Posted URL Change

Main Menu

Getting Mouse coordinates when over a control

Started by peaslee, June 14, 2012, 07:07:42 AM

Previous topic - Next topic

peaslee

I have a dialog with 133 Rich Edit controls used to provide a map-like interface. I am trying to get the x- and y-corrdinate of the mouse when the user clicks in the client area, relative to the client area. I was trying something like this:


.elseif iMsg == WM_LBUTTONDOWN
      invoke Beep, 600, 200        ;test to see if it works
      invoke SetCapture, hDlg
.elseif iMsg == WM_LBUTTONUP
      invoke Beep, 1200, 200
      invoke ReleaseCapture


I get the two beeps if I click anywhere except over a control. I want the coordinates because I have an algorithm the decides whether or not the mouse was dragged (thus scrolling the dialog) or not and over a control (thus opening another dialog with control-specific infomation).

Thanks.

qWord

The coordinates are passed through lParam: low word = x, high word = y
If you need the mouse events from the rich edits, process the EN_MSGFILTER notification. See also EM_SETEVENTMASK.
MREAL macros - when you need floating point arithmetic while assembling!

Farabi

Or you can use "GetCursorPos" from the WinAPI function. http://msdn.microsoft.com/en-us/library/windows/desktop/ms648390(v=vs.85).aspx
http://farabidatacenter.url.ph/MySoftware/
My 3D Game Engine Demo.

Contact me at Whatsapp: 6283818314165

jj2007

Quote from: peaslee on June 14, 2012, 07:07:42 AM
I have a dialog with 133 Rich Edit controls used to provide a map-like interface.

Not a very efficient approach. Have a look at CreatePolygonRgn, FillRgn, FrameRgn, InvertRgn, PaintRgn and in particular PtInRegion.

MichaelW

Judging from this:

http://support.microsoft.com/kb/121960/a

PtInRegion is relatively slow.


;==============================================================================
    include \masm32\include\masm32rt.inc
    .686
    include \masm32\macros\timers.asm
;==============================================================================
    .data
      hInstance HANDLE  0
      hRgn      HRGN    0
      pt        POINT   <>
      rc        RECT    <>
    .code
;==============================================================================

DlgProc proc hwndDlg:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM

    SWITCH uMsg

        CASE WM_INITDIALOG

            invoke SetTimer, hwndDlg, 1, 3000, NULL

        CASE WM_TIMER

            invoke KillTimer, hwndDlg, 1

            invoke GetClientRect, hwndDlg, ADDR rc

            invoke CreateRectRgn, rc.left, rc.top, rc.right, rc.bottom
            mov hRgn, eax

            push ebx

            counter_begin 10000000, REALTIME_PRIORITY_CLASS
                invoke PtInRect, ADDR rc, 100, 100
            counter_end
            printf("%d cycles\n", eax)

            counter_begin 10000000, REALTIME_PRIORITY_CLASS
                invoke PtInRect, ADDR rc, 300, 300
            counter_end
            printf("%d cycles\n", eax)

            counter_begin 10000000, REALTIME_PRIORITY_CLASS
                invoke PtInRegion, hRgn, 100, 100
            counter_end
            printf("%d cycles\n", eax)

            counter_begin 10000000, REALTIME_PRIORITY_CLASS
                invoke PtInRegion, hRgn, 300, 300
            counter_end
            printf("%d cycles\n", eax)

            pop ebx

        CASE WM_COMMAND

            SWITCH wParam

                CASE IDCANCEL

                    invoke EndDialog, hwndDlg, NULL

            ENDSW

        CASE WM_CLOSE

            invoke EndDialog, hwndDlg, NULL

    ENDSW

    return 0

DlgProc endp

;==============================================================================
start:
;==============================================================================

    invoke GetCurrentProcess
    invoke SetProcessAffinityMask, eax, 1

    invoke GetModuleHandle, NULL
    mov   hInstance, eax

    Dialog "Test", \
           "MS Sans Serif",10, \
           WS_VISIBLE or WS_OVERLAPPED or WS_SYSMENU or DS_CENTER, \
           0,0,0,100,100,1024

    CallModalDialog hInstance,0,DlgProc,NULL

    exit
;==============================================================================
end start


Typical results on my Windows 2000 P3 system:

14 cycles
9 cycles
47 cycles
45 cycles

Typical results on my Windows XP P4 (Northwood) system:

10 cycles
9 cycles
19 cycles
15 cycles

Well Microsoft, here's another nice mess you've gotten us into.

jj2007

Depends on what you consider slow - 20 cycles is pretty fast when used e.g. for a world map with 200 regions. One wonders, though, why Microsoft doesn't use the faster code for PtInRegion  ::)

In any case it must be orders of magnitudes faster than handling and testing 200 different RichEdit controls...

peaslee

Quote from: jj2007 on June 15, 2012, 12:38:43 PM
In any case it must be orders of magnitudes faster than handling and testing 200 different RichEdit controls...
I'm sure. But I don't use the RichEdit Controls for anything other than displaying data. Each one represents a lot in a neighborhood. When I drag, scroll; when I just click, I want the coordinates so I can compute which lot, if any, got the hit. In a BASIC program, capturing the mouse did the trick, but I can't get that to work here.

dedndave

capturing the mouse merely forces mouse messages to be sent to a specified window
also - notice that there are a few ways to lose capture, other than ReleaseCapture
maybe you can post a simplified example with source to demonstrate the problem
it is much easier than us asking a bunch of questions   :P

dedndave

maybe what you want to look for is WM_PARENTNOTIFY   :t

Farabi

Oops he wanted it happen when it hover the button area, I did not notify it.
I used to use this code to catch the mouse click

Quote
invoke SetWindowLong,lb,GWL_WNDPROC,addr ListBox1Proc
      mov lbp,eax    ;  lbp is the real listbox procedure, change it with yours



ListBox1Proc proc hWnd:dword,uMsg:dword,wParam:dword,lParam:dword
   
       .if uMsg==WM_RBUTTONUP
           ; Something is clicked. Check the hWnd to determine which control is clicked.
      .endif

   done:
   invoke CallWindowProc,lbp,hWnd,uMsg,wParam,lParam
   
   
   ret
ListBox1Proc endp
http://farabidatacenter.url.ph/MySoftware/
My 3D Game Engine Demo.

Contact me at Whatsapp: 6283818314165

Mr Hippy

You will have to do collision-detection from the application message WM_MOUSEOVER where lParam is made of the LOWORD of the X-coordinate and HIWORD of the Y-coordinate. That is what I have done for a few applications to have a neat little shadow effect on buttons and controls.

peaslee

I think Farabi's approach is easiest for me to understand, but of course I can't get it to work  :icon_rolleyes:

Here's what I've tried:


;this creates the pretty controls
...
.while ebx <= MAXLOTNUMBER
      invoke CreateWindowEx, 0, ADDR RichEditClass, NULL,
         WS_VISIBLE or ES_MULTILINE or WS_CHILD or WS_BORDER,
         [esi].x, [esi].y, ;location
         [esi].w, [esi].h, ;size
         hDlg,             ;parent
         ebx,              ;ID number
         hInstance,
         0
      mov    [esi].hwnd, eax      
      invoke SendMessage,   [esi].hwnd, EM_SETBKGNDCOLOR, 0, 255  ;red
      invoke SetWindowLong, [esi].hwnd, GWL_WNDPROC, ADDR ControlProc
      mov    oldProc, eax
      add    esi, type LOT
      inc    ebx
   .endw
...
ControlProc PROC hWnd:HWND, iMsg:DWORD, wParam:WPARAM, lParam:LPARAM
              .if iMsg == WM_LBUTTONDOWN
      invoke Beep, 400, 500 ;to test
      invoke SetCapture, hMapDlg
   .else
      invoke CallWindowProc, oldProc, hWnd,iMsg,wParam,lParam
   .endif
   xor eax, eax
   ret
ControlProc EndP



qWord

Quote from: peaslee on June 17, 2012, 02:44:58 AM
I think Farabi's approach is easiest for me to understand

easier than this?  :t

.elseif uMsg == WM_CREATE
IDC_RRICHEDIT EQU 100

fn LoadLibrary,"Riched32.dll"

mov esi,rv(CreateWindowEx,0,"RichEdit",0,WS_CHILD or WS_VISIBLE or WS_BORDER,200,200,100,100,hWnd,IDC_RRICHEDIT,0,0)
invoke SendMessage,esi,EM_SETEVENTMASK,0,ENM_MOUSEEVENTS ; <--

.elseif uMsg == WM_NOTIFY
.if wParam == IDC_RRICHEDIT
mov edx,lParam
.if [edx].NMHDR.code == EN_MSGFILTER
;/* process mouse-messages of child control */
.if [edx].MSGFILTER.msg == WM_LBUTTONDOWN
fn MessageBox,0,"rich edit: mouse down","event",0
xor eax,eax
ret
;.elseif uMsg == WM_MOUSEMOVE
;...
.endif
.endif
.endif
MREAL macros - when you need floating point arithmetic while assembling!

Farabi

You should write it like this

Quote
ControlProc PROC hWnd:HWND, iMsg:DWORD, wParam:WPARAM, lParam:LPARAM
              .if iMsg == WM_LBUTTONDOWN
      invoke Beep, 400, 500 ;to test
      invoke SetCapture, hMapDlg
   .else
      ; NOT HERE
   .endif
invoke CallWindowProc, oldProc, hWnd,iMsg,wParam,lParam ; BUT HERE
   xor eax, eax
http://farabidatacenter.url.ph/MySoftware/
My 3D Game Engine Demo.

Contact me at Whatsapp: 6283818314165