AutoHotkey Community

It is currently May 25th, 2012, 3:07 pm

All times are UTC [ DST ]




Post new topic Reply to topic  [ 19 posts ]  Go to page 1, 2  Next
Author Message
PostPosted: August 17th, 2007, 5:31 pm 
Offline

Joined: July 20th, 2007, 10:23 am
Posts: 257
Location: Paris, France
Just a a collection of functions that uses the Windows API message WM_NCHITTEST.
For those who don't know WM_NCHITTEST, this message allows to known which part of a window is at specified coordinates.
This is useful to know if the mouse cursor is over a minimize button for example.

I didn't create a function per value I found in the Microsoft documentation, because I can't make all works. For example, HTHSCROLL is supposed to be returned when over a horizontal scroll bar. But it never worked for me ???
An other example is the HTMENU value. It only work with very simple menus, like thoses found in notepad or wordpad (I think it corresponds to the basic MENU of the Windows API, or CMenu in MFC). But it doesn't work with other menu controls, like those of MS Word, because they are not standard (rebars or something like that).

So, the existing functions are (this is also present is the code)
Window title bar related:
IsOverTitleBar (i.e. MinButton or MaxButton or CloseButton or HelpButton or TitleBarCaption or TitleBarIcon)
IsOverMinButton
IsOverMaxButton
IsOverCloseButton
IsOverHelpButton
IsOverTitleBarCaption
IsOverTitleBarIcon
IsOverTitleSysMenu (same as IsOverTitleBarIcon)

Window borders related:
IsOverBorder (resizable or not)
IsOverResizableBorder (at top, bottom, left, right or corners)
IsOverNonResizableBorder (no difference between top, bottom, left, right and corners)
IsOverResizableLeftBorder
IsOverResizableRightBorder
IsOverResizableTopBorder
IsOverResizableBottomBorder
IsOverResizableTopLeftBorder
IsOverResizableBottomLeftBorder
IsOverResizableTopRightBorder
IsOverResizableBottomRightBorder

Window client area:
IsOverClientArea


Code:
; Script Function:
;    Wraps the windows API message WM_NCHITTEST, that allows to know which part of a window is
;   at specified coordinates.
;
; ******************************************************************************
;
;   IsOverTitleBar (i.e. MinButton or MaxButton or CloseButton or HelpButton or TitleBarCaption or TitleBarIcon)
;   IsOverMinButton
;   IsOverMaxButton
;   IsOverCloseButton
;   IsOverHelpButton
;   IsOverTitleBarCaption
;   IsOverTitleBarIcon
;   IsOverTitleSysMenu (same as IsOverTitleBarIcon)
;   IsOverClientArea
;   IsOverBorder (resizable or not)
;   IsOverResizableBorder (at top, bottom, left, right or corners)
;   IsOverNonResizableBorder (no difference between top, bottom, left, right and corners)
;   IsOverResizableLeftBorder
;   IsOverResizableRightBorder
;   IsOverResizableTopBorder
;   IsOverResizableBottomBorder
;   IsOverResizableTopLeftBorder
;   IsOverResizableBottomLeftBorder
;   IsOverResizableTopRightBorder
;   IsOverResizableBottomRightBorder
;
; ******************************************************************************
;
; From winuser.h & MSDN:
; WM_NCHITTEST = 0x84
; The return value is one of the following values, indicating the position of the cursor hot spot.
; #define HTERROR             (-2)         On the screen background or on a dividing line between windows (same as HTNOWHERE, except that the DefWindowProc function produces a system beep to indicate an error).
; #define HTTRANSPARENT       (-1)         In a window currently covered by another window in the same thread (the message will be sent to underlying windows in the same thread until one of them returns a code that is not HTTRANSPARENT).
; #define HTNOWHERE           0            On the screen background or on a dividing line between windows.
; #define HTCLIENT            1            In a client area.
; #define HTCAPTION           2            In a title bar.
; #define HTSYSMENU           3            In a window menu or in a Close button in a child window.
; #define HTGROWBOX           4            In a size box (same as HTSIZE).
; #define HTSIZE              HTGROWBOX
; #define HTMENU              5            In a menu (works for basic menus like notepad, not for menu **bars like in MS Word)
; #define HTHSCROLL           6            In a horizontal scroll bar.
; #define HTVSCROLL           7            In the vertical scroll bar.
; #define HTMINBUTTON         8            In a Minimize button.
; #define HTMAXBUTTON         9            In a Maximize button.
; #define HTLEFT              10         In the left border of a resizable window (the user can click the mouse to resize the window horizontally).
; #define HTRIGHT             11         In the right border of a resizable window (the user can click the mouse to resize the window horizontally).
; #define HTTOP               12         In the upper-horizontal border of a window.
; #define HTTOPLEFT           13         In the upper-left corner of a window border.
; #define HTTOPRIGHT          14         In the upper-right corner of a window border.
; #define HTBOTTOM            15         In the lower-horizontal border of a resizable window (the user can click the mouse to resize the window vertically).
; #define HTBOTTOMLEFT        16         In the lower-left corner of a border of a resizable window (the user can click the mouse to resize the window diagonally).
; #define HTBOTTOMRIGHT       17         In the lower-right corner of a border of a resizable window (the user can click the mouse to resize the window diagonally).
; #define HTBORDER            18         In the border of a window that does not have a sizing border.
; #define HTCLOSE             20         In a Close button.
; #define HTHELP              21         In a Help button.
;
; ******************************************************************************

IsOverClientArea(x, y, hWnd)
{
   SendMessage, 0x84,, (x & 0xFFFF) | (y & 0xFFFF) << 16,, ahk_id %hWnd%
   return (ErrorLevel == 1)
}
; ------------------------------------------------------------------------------

IsOverTitleBar(x, y, hWnd)
{
   SendMessage, 0x84,, (x & 0xFFFF) | (y & 0xFFFF) << 16,, ahk_id %hWnd%
   if ErrorLevel in 2,3,8,9,20,21
      return true
   else
      return false
}
; ------------------------------------------------------------------------------

IsOverTitleBarCaption(x, y, hWnd)
{
   SendMessage, 0x84,, (x & 0xFFFF) | (y & 0xFFFF) << 16,, ahk_id %hWnd%
   return (ErrorLevel == 2)
}
; ------------------------------------------------------------------------------

IsOverTitleBarIcon(x, y, hWnd)
{
   SendMessage, 0x84,, (x & 0xFFFF) | (y & 0xFFFF) << 16,, ahk_id %hWnd%
   return (ErrorLevel == 3)
}
; ------------------------------------------------------------------------------

IsOverSysMenu(x, y, hWnd)
{
   SendMessage, 0x84,, (x & 0xFFFF) | (y & 0xFFFF) << 16,, ahk_id %hWnd%
   return (ErrorLevel == 3)
}
; ------------------------------------------------------------------------------

IsOverMinButton(x, y, hWnd)
{
   SendMessage, 0x84,, (x & 0xFFFF) | (y & 0xFFFF) << 16,, ahk_id %hWnd%
   return (ErrorLevel == 8)
}
; ------------------------------------------------------------------------------

IsOverMaxButton(x, y, hWnd)
{
   SendMessage, 0x84,, (x & 0xFFFF) | (y & 0xFFFF) << 16,, ahk_id %hWnd%
   return (ErrorLevel == 9)
}
; ------------------------------------------------------------------------------

IsOverCloseButton(x, y, hWnd)
{
   SendMessage, 0x84,, (x & 0xFFFF) | (y & 0xFFFF) << 16,, ahk_id %hWnd%
   return (ErrorLevel == 20)
}
; ------------------------------------------------------------------------------

IsOverHelpButton(x, y, hWnd)
{
   SendMessage, 0x84,, (x & 0xFFFF) | (y & 0xFFFF) << 16,, ahk_id %hWnd%
   return (ErrorLevel == 21)
}
; ------------------------------------------------------------------------------

IsOverBorder(x, y, hWnd)
{
   SendMessage, 0x84,, (x & 0xFFFF) | (y & 0xFFFF) << 16,, ahk_id %hWnd%
   return (ErrorLevel >= 10 && ErrorLevel <= 18)
}
; ------------------------------------------------------------------------------

IsOverResizableBorder(x, y, hWnd)
{
   SendMessage, 0x84,, (x & 0xFFFF) | (y & 0xFFFF) << 16,, ahk_id %hWnd%
   return (ErrorLevel >= 10 && ErrorLevel <= 17)
}
; ------------------------------------------------------------------------------

IsOverNonResizableBorder(x, y, hWnd)
{
   SendMessage, 0x84,, (x & 0xFFFF) | (y & 0xFFFF) << 16,, ahk_id %hWnd%
   return (ErrorLevel == 18)
}
; ------------------------------------------------------------------------------

IsOverResizableLeftBorder(x, y, hWnd)
{
   SendMessage, 0x84,, (x & 0xFFFF) | (y & 0xFFFF) << 16,, ahk_id %hWnd%
   return (ErrorLevel == 10)
}
; ------------------------------------------------------------------------------

IsOverResizableRightBorder(x, y, hWnd)
{
   SendMessage, 0x84,, (x & 0xFFFF) | (y & 0xFFFF) << 16,, ahk_id %hWnd%
   return (ErrorLevel == 11)
}
; ------------------------------------------------------------------------------

IsOverResizableTopBorder(x, y, hWnd)
{
   SendMessage, 0x84,, (x & 0xFFFF) | (y & 0xFFFF) << 16,, ahk_id %hWnd%
   return (ErrorLevel == 12)
}
; ------------------------------------------------------------------------------

IsOverResizableBottomBorder(x, y, hWnd)
{
   SendMessage, 0x84,, (x & 0xFFFF) | (y & 0xFFFF) << 16,, ahk_id %hWnd%
   return (ErrorLevel == 15)
}
; ------------------------------------------------------------------------------

IsOverResizableTopLeftBorder(x, y, hWnd)
{
   SendMessage, 0x84,, (x & 0xFFFF) | (y & 0xFFFF) << 16,, ahk_id %hWnd%
   return (ErrorLevel == 13)
}
; ------------------------------------------------------------------------------

IsOverResizableBottomLeftBorder(x, y, hWnd)
{
   SendMessage, 0x84,, (x & 0xFFFF) | (y & 0xFFFF) << 16,, ahk_id %hWnd%
   return (ErrorLevel == 17)
}
; ------------------------------------------------------------------------------

IsOverResizableTopRightBorder(x, y, hWnd)
{
   SendMessage, 0x84,, (x & 0xFFFF) | (y & 0xFFFF) << 16,, ahk_id %hWnd%
   return (ErrorLevel == 14)
}
; ------------------------------------------------------------------------------

IsOverResizableBottomRightBorder(x, y, hWnd)
{
   SendMessage, 0x84,, (x & 0xFFFF) | (y & 0xFFFF) << 16,, ahk_id %hWnd%
   return (ErrorLevel == 17)
}


Edited 20071509:
Changed
Code:
(Y << 16) | X
by
Code:
(x & 0xFFFF) | (y & 0xFFFF) << 16

So the functions should work on dual monitor


Last edited by Andreone on September 14th, 2007, 11:50 pm, edited 1 time in total.

Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: August 17th, 2007, 8:58 pm 
Offline

Joined: October 17th, 2006, 4:15 pm
Posts: 7501
Location: Australia
Very good. :) Unfortunately, WM_NCHITTEST doesn't work with negative co-ordinates (i.e. on secondary monitor when its to the left of the primary) since the co-ordinates are 16-bit unsigned integers. :(


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: August 17th, 2007, 9:28 pm 
Offline

Joined: July 20th, 2007, 10:23 am
Posts: 257
Location: Paris, France
Too bad, I didn't realize that.
I think that using GetSystemMetrics to have button sizes and a bit of math, almost the same can be done.


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: August 18th, 2007, 1:56 am 
Offline

Joined: February 12th, 2007, 7:54 am
Posts: 2462
I suggest to use
Code:
(X & 0xFFFF) | (Y & 0xFFFF) << 16

I don't know if it'll work with negative coordinates, as no longer on dual monitors, however, worth trying, I suppose.


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: August 18th, 2007, 6:44 am 
Offline

Joined: February 12th, 2007, 7:54 am
Posts: 2462
I modified the script to return the name of the area under the mouse.

Code:
;HT_4294967294 := "ERROR"
;HT_4294967295 := "TRANSPARENT"
HT_0  := "NOWHERE"
HT_1  := "CLIENT"
HT_2  := "CAPTION"
HT_3  := "SYSMENU"
HT_4  := "SIZE"
HT_5  := "MENU"
HT_6  := "HSCROLL"
HT_7  := "VSCROLL"
HT_8  := "MINBUTTON"
HT_9  := "MAXBUTTON"
HT_10 := "LEFT"
HT_11 := "RIGHT"
HT_12 := "TOP"
HT_13 := "TOPLEFT"
HT_14 := "TOPRIGHT"
HT_15 := "BOTTOM"
HT_16 := "BOTTOMLEFT"
HT_17 := "BOTTOMRIGHT"
HT_18 := "BORDER"
HT_19 := "OBJECT"
HT_20 := "CLOSE"
HT_21 := "HELP"

NCHITTEST(x, y, hWnd)
{
   SendMessage, 0x84, 0, (x & 0xFFFF) | (y & 0xFFFF) << 16,, ahk_id %hWnd%
   Return   ErrorLevel >= 0 ? HT_%ErrorLevel% : ErrorLevel = -1 ? "TRANSPARENT" : "ERROR"
}

CoordMode, Mouse, Screen
MouseGetPos, x, y, hWnd
MsgBox, % NCHITTEST(x, y, hWnd)

or

Code:
WM_NCHITTEST()
{
   CoordMode, Mouse, Screen
   MouseGetPos, x, y, z
   SendMessage, 0x84, 0, (x&0xFFFF)|(y&0xFFFF)<<16,, ahk_id %z%
   RegExMatch("ERROR TRANSPARENT NOWHERE CLIENT CAPTION SYSMENU SIZE MENU HSCROLL VSCROLL MINBUTTON MAXBUTTON LEFT RIGHT TOP TOPLEFT TOPRIGHT BOTTOM BOTTOMLEFT BOTTOMRIGHT BORDER OBJECT CLOSE HELP", "(?:\w+\s+){" . ErrorLevel+2&0xFFFFFFFF . "}(?<AREA>\w+\b)", HT)
   Return   HTAREA
}

MsgBox, % NCHITTEST()


Last edited by Sean on July 6th, 2008, 7:16 am, edited 1 time in total.

Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: August 18th, 2007, 12:04 pm 
Offline

Joined: October 17th, 2006, 4:15 pm
Posts: 7501
Location: Australia
Sean wrote:
I suggest to use
Code:
(X & 0xFFFF) | (Y & 0xFFFF) << 16

I don't know if it'll work with negative coordinates, as no longer on dual monitors, however, worth trying, I suppose.
Because AHK integer math is 64-bit, I think x & 0xFFFF would truncate/remove/ignore the sign bit, always resulting in a value between 0 and 0xFFFF. I think the reason "x | y<<16" doesn't work is that the sign bit is in a different position (again, because AHK integer math is 64-bit.) I don't understand it fully, however, the following seems to work:
Code:
_CompactPoint( x, y )
{
    x := (x<0) ? 0x10000+x : x  ; 0x10000 is UShort_max_value+1
    y := (y<0) ? 0x10000+y : y
    return x | (y<<16)
}
(Values are manually converted to 16-bit unsigned values to mimic the bit-pattern of a 16-bit signed integer.)

You could check for co-ordinates outside the range of -0x8000 and 0x7FFF (it seems the low- and high-order words mentioned in MSDN are 16-bit signed integers), but if that were to happen, WM_NCHITTEST won't work anyway.


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: August 18th, 2007, 12:27 pm 
Offline

Joined: February 12th, 2007, 7:54 am
Posts: 2462
lexikos wrote:
Because AHK integer math is 64-bit, I think x & 0xFFFF would truncate/remove/ignore the sign bit, always resulting in a value between 0 and 0xFFFF.

The sign bit is a relative concept. Surely x & 0xFFFF will clear the sign bit as int64 and int32, however, will preserve it as int16 assuming the integer is in the range -32768 <= x <= 32767. So,

Code:
(x & 0xFFFF) | (y & 0xFFFF) << 16

does exactly the same thing as
Code:
_CompactPoint( x, y )
{
    x := (x<0) ? 0x10000+x : x  ; 0x10000 is UShort_max_value+1
    y := (y<0) ? 0x10000+y : y
    return x | (y<<16)
}


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: August 18th, 2007, 1:07 pm 
Offline

Joined: October 17th, 2006, 4:15 pm
Posts: 7501
Location: Australia
You're right; that works. I'm sure I tried "& 0xFFFF" (at least partially?), but I must've done something wrong (like forgetting parentheses?)
Quote:
however, will preserve it as int16
True, but as I said, integer math in AutoHotkey is always 64-bit; there are no int16s. The sign bit is technically lost, but because of the way negative values are represented, the value is preserved* when truncating the high-order bytes. (-1 is 0xFFFFFFFFFFFFFFFF; when truncated is 0xFFFF, which is the same as -1 for an int16.)

* If, as you said, "the integer is in the range -32768 <= x <= 32767"


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: August 18th, 2007, 1:31 pm 
Offline

Joined: February 12th, 2007, 7:54 am
Posts: 2462
lexikos wrote:
The sign bit is technically lost, but because of the way negative values are represented, the value is preserved* when truncating the high-order bytes.

Yes, that's the heart of the trick. Another one I frequently use, e.g. for Ushort to short, is

Code:
x<<48>>48


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: September 14th, 2007, 11:43 pm 
Offline

Joined: July 20th, 2007, 10:23 am
Posts: 257
Location: Paris, France
I just realized I never updated my first post the coordinate trick suggestion.
Code:
(x & 0xFFFF) | (y & 0xFFFF) << 16

Now its done :)
Thanks everybody


Report this post
Top
 Profile  
Reply with quote  
 Post subject: OLD THREAD UPDATED
PostPosted: April 2nd, 2009, 8:21 pm 
Andreone wrote:
For example, HTHSCROLL is supposed to be returned when over a horizontal scroll bar. But it never worked for me ???

You'll have to use the handle of the control which has the scroll bar(s), e.g. "Edit1", "SystreeView321".


Report this post
Top
  
Reply with quote  
 Post subject: OLD THREAD UPDATED
PostPosted: April 3rd, 2009, 7:17 pm 
Actually I meant: you'll have to specify control in SendMessage.


Report this post
Top
  
Reply with quote  
 Post subject:
PostPosted: December 4th, 2009, 7:32 pm 
Online

Joined: March 27th, 2008, 2:14 pm
Posts: 700
IsOverResizableBottomLeftBorder compares errorlevel to the wrong value (it's supposed to be 16, not 17 according to your nchittest values table at the top of the script)

_________________
Scripts - License


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: October 26th, 2010, 9:50 am 
Offline

Joined: December 8th, 2008, 3:39 am
Posts: 8
Location: Spain
Any way to make this work correctly for aero enabled windows?

For example, here it is returning "MAXBUTTON" when it should clearly be "CLOSE":

Image


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: April 8th, 2011, 6:40 am 
Offline

Joined: October 5th, 2007, 2:21 am
Posts: 138
Location: Bundaberg (Bundy), Qld, Australia
this mod returns HSCROLL and VSCROLL when over the scroll bar in notepad. alas doesn't work in explorer. would love to find what the problem is.
Code:
;HT_4294967294 := "ERROR"
;HT_4294967295 := "TRANSPARENT"
HT_0  := "NOWHERE"
HT_1  := "CLIENT"
HT_2  := "CAPTION"
HT_3  := "SYSMENU"
HT_4  := "SIZE"
HT_5  := "MENU"
HT_6  := "HSCROLL"
HT_7  := "VSCROLL"
HT_8  := "MINBUTTON"
HT_9  := "MAXBUTTON"
HT_10 := "LEFT"
HT_11 := "RIGHT"
HT_12 := "TOP"
HT_13 := "TOPLEFT"
HT_14 := "TOPRIGHT"
HT_15 := "BOTTOM"
HT_16 := "BOTTOMLEFT"
HT_17 := "BOTTOMRIGHT"
HT_18 := "BORDER"
HT_19 := "OBJECT"
HT_20 := "CLOSE"
HT_21 := "HELP"

NCHITTEST(x, y, hWnd)
{
   SendMessage, 0x84, 0, (x & 0xFFFF) | (y & 0xFFFF) << 16,, ahk_id %hWnd%
   Return   ErrorLevel >= 0 ? HT_%ErrorLevel% : ErrorLevel = -1 ? "TRANSPARENT" : "ERROR"
}

CoordMode, Mouse, Screen
MouseGetPos, x, y,, hWnd,2
MsgBox, % NCHITTEST(x, y, hWnd)


Report this post
Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 19 posts ]  Go to page 1, 2  Next

All times are UTC [ DST ]


Who is online

Users browsing this forum: Google Feedfetcher, JamixZol and 31 guests


You can post new topics in this forum
You can reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Powered by phpBB® Forum Software © phpBB Group