How to swiftly move window without TitleBar and border?

Started by CoR, March 30, 2007, 09:20:41 PM

Previous topic - Next topic

CoR

New code is bolded. It's meant to move window without border and TitleBar. And it works very, very smoothly  :cheekygreen: But it can not handle rapid mouse movement. Here's the code with a few questions at the end...

Quote@@:;__________________no return value!!!!!
cmp uMsg,WM_MOUSEMOVE
jne @f

test wParam,MK_CONTROL            ;is CTRL pressed
jz NotCtr                                     ;if not goto NotCtr
test wParam,MK_LBUTTON            ;is Left mouse pressed
jz EndMouseMove                         ;if not goto EndMouseMove 

;move window through lParam x.y
mov eax,lParam                                         ;new mouse position
and eax,65535 ;FFFFh                                ;LOW word  for x
sub eax,WInputFlagMousePoint.x             ;new-old=move difference
add WInputFlagX,eax                                ;add window pos + move differemce

mov eax,lParam                                         ;new mouse position
shr eax,16                                                 ;HI word for Y
sub eax,WInputFlagMousePoint.y             ;new-old=move difference
add WInputFlagY,eax                                ;add win pos + move diference
invoke MoveWindow,hWnd,WInputFlagX,WInputFlagY,WInputFlagWidth,WInputFlagHeight,TRUE
;invoke SetWindowPos,hWnd,HWND_TOP,WInputFlagX,WInputFlagY,WInputFlagWidth,WInputFlagHeight,SWP_NOSIZE

jmp EndMouseMove
NotCtr:
invoke SetClassLong, hWnd,GCL_HCURSOR,hcurArrow
invoke SetCursor, hcurArrow

EndMouseMove:
;-----end wm_mousemove-----



@@:;____________________return 0
cmp uMsg,WM_LBUTTONDOWN
jne @F
mov eax,lParam
and eax,0FFFFh                             ;LO byte for X
mov WInputFlagMousePoint.x,eax   
mov eax,lParam
shr eax,16                                     ;HI byte for y
mov WInputFlagMousePoint.y,eax

  test wParam,MK_CONTROL
  jz NotCtrlP
invoke SetClassLong, hWnd,GCL_HCURSOR,hcurGrabbed
invoke SetCursor, hcurGrabbed
        xor eax,eax
        ret
NotCtrlP:
xor eax,eax
ret
;--------end wm_lbutondown-------------------

Questions:
Is there better way to move window without border?
This code does the job if you move mouse by slow/normal paste. If mouse movement is too rapid or fast, cursor simply leaves client area. It looks like window is too slow to stay below cursor. This does not happen if you grab and move window by the TitleBar. No matter how fast you move it. Any idea how to replicate it with window without border and TitleBar?

ramguru

oh man... :dazzled: :lol

.elseif eax==WM_LBUTTONDOWN
invoke SendMessage, hWnd, WM_NCLBUTTONDOWN, HTCAPTION, 0

LimoDriver

Quote

.elseif eax==WM_LBUTTONDOWN
    invoke SendMessage, hWnd, WM_NCLBUTTONDOWN, HTCAPTION, 0


The problem with the above code is that you cannot drag the window's imaginary title above the desktop top side.
Try it, it will bounce down upon mouse button release, due to windows trying to keep the title available (even though it's non-existant).

The following code, although a bit long, will drag the window without any unexpected hops or twitches.


; #################################################################################################

;    DragWindow by LimoDriver [30/03/2007]

; #################################################################################################
     
     .data?

     gx_Pnt      POINT <?>

     .code

; #################################################################################################

     DragWindow proc gh_Wnd : DWORD, d_Msg : DWORD
     ;{
          LOCAL x_Rct : RECT

; -------------------------------------------------------------------------------------------------
     
          mov       eax, d_Msg
         
@@:       cmp       eax, WM_RBUTTONDOWN
          jnz       @F
          ;{   
               invoke    LoadCursor, 0, IDC_SIZEALL
               invoke    SetCursor, eax
               invoke    GetCursorPos, addr gx_Pnt
               invoke    SetCapture, gh_Wnd
               jmp       @DW_E
          ;}

; -------------------------------------------------------------------------------------------------

@@:       cmp       eax, WM_RBUTTONUP
          jnz       @F
          ;{
               invoke    ReleaseCapture
               jmp       @DW_E
          ;}

; -------------------------------------------------------------------------------------------------

@@:       cmp       eax, WM_MOUSEMOVE
          jnz       @F
          ;{
               invoke    GetCapture
               cmp       eax, gh_Wnd       
               jnz       @F
               ;{
                    push      gx_Pnt.y               
                    push      gx_Pnt.x
                   
                    invoke    GetCursorPos, addr gx_Pnt
                    invoke    GetWindowRect, gh_Wnd, addr x_Rct
                   
                    mov       ecx, gx_Pnt.x
                    pop       eax
                    sub       ecx, eax
                    add       ecx, x_Rct.left
     
                    mov       edx, gx_Pnt.y
                    pop       eax
                    sub       edx, eax
                    add       edx, x_Rct.top
     
                    invoke    SetWindowPos, gh_Wnd, 0, ecx, edx, 0, 0, SWP_NOZORDER or SWP_NOSIZE
                    jmp       @DW_E
               ;}     
          ;}

; -------------------------------------------------------------------------------------------------

@@:       return    d_Msg

@DW_E:    return    0
     ;}
     DragWindow endp
         
; #################################################################################################

ramguru

Quote from: LimoDriver on March 30, 2007, 09:49:12 PM
The problem with the above code is that you cannot drag the window's imaginary title above the desktop top side.
Try it, it will bounce down upon mouse button release, due to windows trying to keep the title available (even though it's non-existant).
I wouldn't call it a problem, rather a good feature. Why would I want to drag a window somewhere outside desktop, say: x,y(100,-10). This ensures that there will be always a small part of window accessible on the desktop...

LimoDriver

QuoteWhy would I want to drag a window somewhere outside desktop, say: x,y(100,-10). This ensures that there will be always a small part of window accessible on the desktop...

The code I pasted also ensures that a small part of the window is always accessible, since you cannot drag the window to a point on screen beyond the desktop.
The only difference is that it's truly up to the application developers call to decide on the minimum and maximum bounding boxes, instead of windows enforcing its "show title" will - on a usually skinned window without the actual title.

Check out any proper application that supports drag anywhere on its body frame (any self respecting media player, for example) - they all have it coded properly, and not via WM_NCLBUTTONDOWN.

ramguru

Don't take me wrong, I'm not afraid of coding, nor I'm envy of few extra code lines, but when it's not worth it I'd rather keep things simple...

LimoDriver

Quotebut when it's not worth it I'd rather keep things simple...

This is most definitely true. For instance, if we're just dragging child controls from within the main application frame, WM_NCLBUTTONDOWN is a savior.

CoR

Hello guys :)
Thank you a lot for your prompt response. I had (still have) some odd problems with cable internet so I could not reply sooner.
Anyway, I am amazed by your knowledge. Thanks again!

Now, lets return to asm  :wink

ramguru,
Your solution works. It's fast, simple, almost flawless. I even do not mind if it tries to show non existing TitleBar. Bad thing is that WM_NCLBUTTONDOWN somehow blocks cursor changing. Another bad thing is that I have no clue WHY it works. And how to implement it if I ever decide to "drag child controls"

LimoDriver,
You've posted some mean code dude  :wink First to ask about DragWindow proc:
IF I do invoke DragWindow param1, param2 in WinProc and IF there are no ret's in it... I'll be able to do one more check for WM_'s I already checked in DragWindow. Is it good way to summarize code for WinProc I might use in future?

F. you posted works because of SetCapture, GetCapture... Nice solution btw  :8) I tried to implement it in my previously posted code for learning purposes. And it works 50%  :green Any rapid moving window to the right or down is fast as it should be. Not a grip lost.

BUT (bigger than J.Lo's) if you move window up or left - it disappears completely!!! I thought about it for a while and finally I realize that window receives a NEGATIVE value for X and/or Y through WM_MOUSEMOVE lParam!!! Because mouse is moved from client area and X.Y are relative to window's top left corner! Isn't that lovely?

Do anyone know how are represented those negative values in lParam hi and lo word. How should I properly convert it in dword values. And last but maybe most important question:
How do we add, sub, signed numbers?!?


ramguru

OK imagine you're using SetCapture and your cursor suddenly appears outside client area
so this is how I checked in one of my program
mov    ecx, lParam
shr    ecx, 16 ; ecx --> y
.if ecx > 0F000h ; if cx < 0
   invoke do_action
.endif

FFFF0000 (0,-1)
FFFE0001 (1,-2)


How to convert word negative to dword negative:
mov    ecx, lParam
shr    ecx, 16  ; high-order negative
or    ecx, 0FFFF0000h ; whole reg negative


How to add,sub:
simply, if whole reg negative
you simply
mov ecx, -1 ; ecx == FFFFFFFF
add ecx, 1 ; ecx == 0 because of overflow [1]00000000

mov ecx, -1 ; ecx == FFFFFFFF
sub ecx, 1 ; ecx == FFFFFFFE




CoR

Mmmmmm... So you are saying that I am abusing sub/add  :wink And I see why!
I did this :
mov eax,lParam                  ;new mouse position
shr eax,16                      ;HI word for Y
sub eax,WInputFlagMousePoint.y  ;new-old=move difference
add WInputFlagY,eax             ;add win pos + move diference

In C/basic it would work: mouse.y=oldmouse.y+mousediference
if mousediference is negative it would be correctly subtracted from oldmouse.y. In my code it threats it like positive value and sets window far away from desktop.

Basically I always have to check if result is negative and write appropriate code! I guess I wanted some mathematical shortcut  :wink
Thank you ramguru  :U

p.s. I am not totally a lost cause :wink   I manage to convert negative word to negative dword correctly! Other two examples are going to be great help to me. Thanks man!

LimoDriver

Quote from: CoR on April 01, 2007, 06:42:13 PM
IF I do invoke DragWindow param1, param2 in WinProc and IF there are no ret's in it... I'll be able to do one more check for WM_'s I already checked in DragWindow. Is it good way to summarize code for WinProc I might use in future?

Well everyone wants to write his own version of WinProc.
When I have large applications, I usually separate everything regarding certian actions into separate mini-WndProc's

This way, when you're done with something, you just dub it done, and never reopen the file again (in this case DragWindow).

It's possible that more than one function will check for the same WM_ but this is utterly irrelevant unless you're writing... writing... no, trust me, it's utterly irrelevant :)

The current code is written in a way that it will return 0 if the DragWindow function has actually done something with the WM_. This way, upon return, you can just ret from the main WndProc if you're sure that you don't need any of the WM_'s included in DragWindow anymore.



CoR

All right  :bg I manage negative numbers and here's the code:

@@:;_______________________no return value!!!!!
cmp uMsg,WM_MOUSEMOVE
jne @f

test wParam,MK_CONTROL      ;is CTRL pressed
jz NotCtr                   ;if not goto NotCtr
test wParam,MK_LBUTTON      ;is Left mouse pressed
;jz EndMouseMove             ;if not goto EndMouseMove 
jz EndMM

invoke    GetCapture
cmp eax,hWnd
;jne EndMouseMove
jne EndMM

; y   x    x, y  = lParam
;FFFF0000 (0,-1)
;FFFE0001 (1,-2)
mov eax,lParam                             ;new mouse position
and eax,00000000000000001111111111111111b  ;65535 ;FFFFh                  ;LOW word  for X
      test ax,1000000000000000b ; 08000h  to see if no, is positive
      jz poz                                                jmp if it is   
      or    eax, 0FFFF0000h                  ;if negative, make it dword negative
sub eax,ClientAreaMouseHP.x ;new-old=move difference
add WInputX,eax                        ;add window pos + move differemce
jmp y
poz:
sub eax,ClientAreaMouseHP.x ;new-old=move difference
add WInputX,eax                        ;add window pos + move differemce

y:
mov eax,lParam                 ;new mouse position
shr eax,16                     ;HI word for Y
      test ax,1000000000000000b
      jz poz1
      or    eax, 0FFFF0000h
sub eax,ClientAreaMouseHP.y ;new-old=move difference
add WInputY,eax                     ;add win pos + move diference
jmp wpiMove
poz1:
sub eax,ClientAreaMouseHP.y ;new-old=move difference
add WInputY,eax                     ;add win pos + move diference
wpiMove:
;invoke MoveWindow,hWnd,WInputX,WInputY,WInputWidth,WInputHeight,TRUE
invoke SetWindowPos,hWnd,HWND_TOP,WInputX,WInputY,WInputWidth,WInputHeight,SWP_NOSIZE
jmp EndMM

NotCtr:
invoke SetClassLong, hWnd,GCL_HCURSOR,hcurArrow
invoke SetCursor, hcurArrow

EndMM:
;------------------------------end wm_mousemove------------------------------

CoR

Quote from: LimoDriver on March 30, 2007, 11:01:37 PM
This is most definitely true. For instance, if we're just dragging child controls from within the main application frame, WM_NCLBUTTONDOWN is a savior.

How do you move child controls? Or to be more precise I want to move edit control with mouse. With end goal to stretch edit control little more over all client area and to be able to move whole window clicking on that edit area?

ramguru

How do you want to move child controls? - implement splitter window or something like resource editor does: resize, move ?

CoR

Exactly like advanced resource editor! First to move only edit control, and after to add CTRL+LBUTTONDOWN to move edit resource and  whole window (because only edit control will be visible)