Well, I'm back. (Apparently I stayed away long enough for my account to be canceled.)
My question this time is this: how can I tap into mouse messages for the entire Windows screen?
What I'm thinking of are programs that can use the mouse outside of their own windows/client areas. One example that I use is my paint program, Paint Shop Pro, which has a screen-capture function that allows me to marquee-select any area of any window on the desktop. Dunno how they do this, but it works.
I thought of trying to subclass the desktop window:
; Subclass the desktop:
CALL GetDesktopWindow
MOV DesktopHandle, EAX
INVOKE SetWindowLong, DesktopHandle, GWL_WNDPROC, ADDR DesktopProc
MOV DesktopProcPtr, EAX
but then I read more about SetWindowLong(): if you want to change the address of the window procedure for a window, "You cannot change this attribute if the window does not belong to the same process as the calling thread." D'oh!
So how could I do this? What I'm trying to do is pretty simple: I'd just like to be able to maquee-select an area of the screen, then display the dimensions in pixels of this area. Seems like that should be pretty simple, no?
Edit: By "marquee select" what I mean is to click anywhere on the screen and drag an outline, then measure the rectangle, possibly while being dragged, or after the mouse button is let go.
Thanks in advance for any help!
(Oh, and I did try traditional mouse capture (via SetCapture() ); couldn't get that to work either.)
i don't think they let you subclass the desktop window
but, you might be able capture the mouse (problem - if the OS or some other program captures, you lose capture)
maybe a hook on the mouse ?
the WindowFromPoint function might also be useful
Quote from: dedndave on March 01, 2014, 02:58:39 PM
the WindowFromPoint function might also be useful
Hmm; not sure how knowing which window the mouse is over could be useful. All I know is that PSP lets you click and drag an outline anywhere on the screen (as well as capture what's inside the rectangle).
One method is to capture the mouse.
;==============================================================================
; Build as a console app.
;==============================================================================
include \masm32\include\masm32rt.inc
;==============================================================================
.data
.code
;==============================================================================
DlgProc proc hwndDlg:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM
SWITCH uMsg
CASE WM_INITDIALOG
CASE WM_LBUTTONDOWN
invoke SetCapture, hwndDlg
CASE WM_LBUTTONUP
invoke ReleaseCapture
CASE WM_MOUSEMOVE
loc 0,0
;----------------------------------------------------------
; The 16-bit cursor coordinates returned in lParam must be
; sign-extended to 32 bits because client coordinates to
; the left of and/or above the client area are negative.
;----------------------------------------------------------
mov eax, lParam
mov edx, eax
movsx eax, ax
shr edx, 16
movsx edx, dx
printf("%d %d ",eax,edx)
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:
;==============================================================================
Dialog "Test", \
"MS Sans Serif",10, \
WS_OVERLAPPED or WS_SYSMENU or DS_CENTER, \
0,0,0,80,60,1024
CallModalDialog NULL,0,DlgProc,NULL
exit
;==============================================================================
end start
I have used this technique to capture a window to a bitmap file, but I have never tried dragging a selection rectangle, or anything similar.
Have a look at a tool in the "tools" directory of MASM32 called "Getcolor". It shows how to use GetCapture".
I don't seem to have that program in my tools folder. I got MASM32 more than a year ago; has it been added since then?. Any chance you could post a zip of it here? (Don't want to reload the package just yet.)
MichaelW, I don't see how that could work for me. Wouldn't the mouse click (resulting in WM_LBUTTONDOWN being received) have to be in one of MY windows? Otherwise, I won't get this message and won't be able to capture the mouse. Or am I missing something there? Remember, I want to be able to click anywhere on the screen, not necessarily in any of my program's areas.
when a window has mouse capture, all mouse messages (movement, clicks) are sent to the window that has capture
the only trick to mouse capture is understanding the relationship with WM_CAPTURECHANGED
i have played with it quite a bit (movable marker lines, sizable windows, etc)
rather than executing "release" code, directly....
you just call ReleaseCapture
then put the "release" code in the WM_CAPTURECHANGED handler
that way, if the system releases capture (for whatever reason) - or another window grabs capture, your release code is executed
i mentioned WindowFromPoint because of the following scenerio....
let's say you have capture - all the mouse messages come to your window
in some cases, you may want to pass those messages to the window that would have received them if you didn't have capture
so, you could get WindowFromPoint, then SendMessage to "forward" messages
i really think that a mouse hook is more in order for this, though - you'll have to experiment
http://msdn.microsoft.com/en-us/library/windows/desktop/ms632589%28v=vs.85%29.aspx (http://msdn.microsoft.com/en-us/library/windows/desktop/ms632589%28v=vs.85%29.aspx)
the problem is - the Desktop uses the drag-selection outline to select a group of icons
that's very different from selecting a graphic region
it might require some sort of Shell Extension Handler
http://msdn.microsoft.com/en-us/library/windows/desktop/cc144067%28v=vs.85%29.aspx (http://msdn.microsoft.com/en-us/library/windows/desktop/cc144067%28v=vs.85%29.aspx)
hopefully, that gives you some ideas :biggrin:
if you find that mouse capture is workable....
here is a simple example that demonstrates the use of WM_CAPTURECHANGED
it uses mouse capture to create movable dividers
Quote from: NoCforMe on March 01, 2014, 02:35:15 PMEdit: By "marquee select" what I mean is to click anywhere on the screen and drag an outline, then measure the rectangle, possibly while being dragged, or after the mouse button is let go.
A simple solution would be to create a snapshot of the current desktop, which is present in a popup window that covers the desktop. The actual selection/measurement is then done by the popup window.
If the content of the Desktop does change while "measurement", layered windows may be a solution (e.g. a semi-transparent overlay).
For mouse capture info, I got a lot of mileage from Iczelion's tutorial 24. It had everything and more than what I needed.
hth,
farrier
Quote from: qWord on March 02, 2014, 11:57:52 AMA simple solution would be to create a snapshot of the current desktop, which is present in a popup window that covers the desktop. The actual selection/measurement is then done by the popup window.
Similar: A transparent window that draws rectangles using GetWindowDC. I attach a draft version in plain Masm32 - no time to finish it, but you'll get the idea.
The API TrackMouseEvent can be of good use.
In the attachment an example using layered windows. The trick is to create an semi-transparent overlay whereas the alpha value is nonzero - due this all mouse messages are send to the overlay window.
include \masm32\include\masm32rt.inc
.686
.mmx
.xmm
IDBTN_SELECT EQU 100
IDCTL_SELECTION EQU 101
COLOR_KEY EQU 0ff00ffh
CONST_ALPHA EQU 40 ; for 32bpp: 1+, 16bpp: 5+
COLOR_OVERLAY EQU 0333333h
DELTA_WAIT EQU 100
FRAME_WIDTH EQU 3
FRAME_COLOR EQU 0ffh
WM_NEW_SELECTION EQU WM_USER+100
WndProc proto hWnd:HWND,uMsg:UINT,wParam:WPARAM,lParam:LPARAM
OverlayProc proto hWnd:HWND,uMsg:UINT,wParam:WPARAM,lParam:LPARAM
FrameProc proto hWnd:HWND,uMsg:UINT,wParam:WPARAM,lParam:LPARAM
.const
szMainClass db "Win32Class",0
szOverlayClass db "OverlayClass32",0
szFrameClass db "FrameClass32",0
.data?
g_hInstance HINSTANCE ?
;/* gloabl variables for simplification :-D */
g_hMainWnd HWND ?
g_hOverlayWnd HWND ?
g_hStaticImg HWND ?
g_hStaticTxt HWND ?
g_hWndFrame HWND ?
g_rcFrame RECT <>
.code
main proc
LOCAL wcex:WNDCLASSEX
LOCAL msg:MSG
mov g_hInstance,rv(GetModuleHandle,0)
mov wcex.hInstance,eax
mov wcex.cbSize,SIZEOF WNDCLASSEX
mov wcex.style, CS_HREDRAW or CS_VREDRAW
mov wcex.lpfnWndProc, OFFSET WndProc
mov wcex.cbClsExtra,NULL
mov wcex.cbWndExtra,0
mov wcex.hbrBackground,rv(GetStockObject,WHITE_BRUSH)
mov wcex.lpszMenuName,NULL
mov wcex.lpszClassName,OFFSET szMainClass
mov wcex.hIcon,rv(LoadIcon,NULL,IDI_APPLICATION)
mov wcex.hIconSm,eax
mov wcex.hCursor,rv(LoadCursor,NULL,IDC_ARROW)
invoke RegisterClassEx, ADDR wcex
mov wcex.lpfnWndProc, OFFSET OverlayProc
mov wcex.hbrBackground,0
mov wcex.lpszClassName,OFFSET szOverlayClass
invoke RegisterClassEx, ADDR wcex
mov wcex.lpfnWndProc, OFFSET FrameProc
mov wcex.lpszClassName,OFFSET szFrameClass
invoke RegisterClassEx, ADDR wcex
fn CreateWindowEx,0,OFFSET szMainClass,"select region",WS_VISIBLE or WS_SYSMENU or WS_SIZEBOX or WS_MINIMIZEBOX or WS_MAXIMIZEBOX or WS_CLIPCHILDREN,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,0,0,g_hInstance,0
.while 1
invoke GetMessage,ADDR msg,NULL,0,0
.break .if !eax || eax == -1
invoke TranslateMessage, ADDR msg
invoke DispatchMessage, ADDR msg
.endw
invoke ExitProcess,msg.wParam
main endp
;/* make sure that left <= right and top <= bottom */
checkRect proc pRect: ptr RECT
mov eax,pRect
mov ecx,[eax].RECT.left
mov edx,[eax].RECT.right
.if ecx > edx
mov [eax].RECT.left,edx
mov [eax].RECT.right,ecx
.endif
mov ecx,[eax].RECT.top
mov edx,[eax].RECT.bottom
.if ecx > edx
mov [eax].RECT.top,edx
mov [eax].RECT.bottom,ecx
.endif
ret
checkRect endp
;/* main window */
WndProc proc uses ebx esi edi hWnd:HWND,uMsg:UINT,wParam:WPARAM,lParam:LPARAM
LOCAL sz[128]:CHAR
.if uMsg == WM_CLOSE
invoke DestroyWindow,hWnd
.elseif uMsg == WM_DESTROY
.if rv(SendMessage,g_hStaticImg,STM_GETIMAGE,IMAGE_BITMAP,0)
fn DeleteObject,eax
.endif
fn PostQuitMessage,NULL
.elseif uMsg == WM_CREATE
mrm g_hMainWnd,hWnd
fn CreateWindowEx,0,"button","Select",WS_VISIBLE or WS_CHILD,0,0,100,30,hWnd,IDBTN_SELECT,g_hInstance,0
fnx g_hStaticImg = CreateWindowEx,0,"static",0,WS_CHILD or WS_VISIBLE or SS_BITMAP or WS_BORDER,5,35,100,100,hWnd,0,g_hInstance,0
fnx g_hStaticTxt = CreateWindowEx,0,"static",0,WS_CHILD or WS_VISIBLE,103,0,200,30,hWnd,0,g_hInstance,0
fn SendMessage,g_hStaticImg,STM_SETIMAGE,IMAGE_BITMAP,rv(CreateCompatibleBitmap,rv(GetDC,0),10,10)
.elseif uMsg == WM_COMMAND && wParam == BN_CLICKED SHL 16 OR IDBTN_SELECT
.if !g_hOverlayWnd
fnx esi = GetSystemMetrics,SM_CXSCREEN
fnx edi = GetSystemMetrics,SM_CYSCREEN
;/* hide this window and create screen-overlay */
invoke ShowWindow,hWnd,SW_MINIMIZE
fnx g_hOverlayWnd = CreateWindowEx,WS_EX_LAYERED OR WS_EX_TOPMOST,OFFSET szOverlayClass,0,WS_VISIBLE OR WS_POPUP,0,0,esi,edi,0,0,g_hInstance,0
.endif
.elseif uMsg == WM_NEW_SELECTION
mov g_hOverlayWnd,0
mov eax,wParam
.if eax
;/* process new selection */
mov ecx,[eax].RECT.right
mov edx,[eax].RECT.bottom
sub ecx,[eax].RECT.left
sub edx,[eax].RECT.top
fn wsprintf,&sz,"x: %i, y: %i, w: %i, h: %i",[eax].RECT.left,[eax].RECT.top,ecx,edx
fn SendMessage,g_hStaticTxt,WM_SETTEXT,0,&sz
push rv(SendMessage,g_hStaticImg,STM_GETIMAGE,IMAGE_BITMAP,0)
fn SendMessage,g_hStaticImg,STM_SETIMAGE,IMAGE_BITMAP,lParam
pop eax
.if eax
invoke DeleteObject,eax
.endif
.endif
.else
invoke DefWindowProc,hWnd,uMsg,wParam,lParam
ret
.endif
xor eax,eax
ret
WndProc endp
;/**
; * This window is transparent and occupies the whole screen.
; * Actual the window is draw with an low alpha value to make sure that
; * mouse messages are received.
; * When dragging starts, a layered window (hit-transparent) is created that
; * shows the selection-frame.
; */
OverlayProc proc uses ebx esi edi hWnd:HWND,uMsg:UINT,wParam:WPARAM,lParam:LPARAM
LOCAL ps:PAINTSTRUCT
LOCAL hBr:HBRUSH
LOCAL rect:RECT,w:SDWORD,h:SDWORD
.if uMsg == WM_CLOSE || (uMsg == WM_KEYDOWN && wParam == VK_ESCAPE)
fn ShowWindow,g_hMainWnd,SW_RESTORE
fn SendMessage,g_hMainWnd,WM_NEW_SELECTION,0,0
fn DestroyWindow,hWnd
.elseif uMsg == WM_DESTROY
.elseif uMsg == WM_CREATE
;/**
; * Draw window with alpha value > 0 thus
; * mouse messages are send to this window.
; */
invoke SetLayeredWindowAttributes,hWnd,0,CONST_ALPHA,LWA_ALPHA
invoke SetForegroundWindow,hWnd
mov g_hWndFrame,0
.elseif uMsg == WM_LBUTTONDOWN
.if !g_hWndFrame
;/* show frame */
fnx esi = GetSystemMetrics,SM_CXSCREEN
fnx edi = GetSystemMetrics,SM_CYSCREEN
fnx g_hWndFrame = CreateWindowEx,WS_EX_LAYERED or WS_EX_TRANSPARENT or WS_EX_TOPMOST,OFFSET szFrameClass,0,WS_VISIBLE OR WS_POPUP,0,0,1,1,hWnd,0,g_hInstance,0
fn GetCursorPos,&g_rcFrame
.endif
.elseif uMsg == WM_LBUTTONUP
.if g_hWndFrame
mov g_hWndFrame,0
;/* destroy this window (and g_hWndFrame) */
invoke DestroyWindow,hWnd
invoke Sleep,DELTA_WAIT
;/* get image from region */
fn RtlMoveMemory,&rect,&g_rcFrame,RECT
fn checkRect,&rect
mov ecx,rect.right
mov edx,rect.bottom
sub ecx,rect.left
sub edx,rect.top
mov w,ecx
mov h,edx
fnx esi = GetDC,0
fnx ebx = CreateCompatibleDC,esi
fnx edi = SelectObject,ebx,rv(CreateCompatibleBitmap,esi,w,h)
invoke BitBlt,ebx,0,0,w,h,esi,rect.left,rect.top,SRCCOPY
fnx edi = SelectObject,ebx,edi
fn DeleteDC,ebx
;/* send result */
fn SendMessage,g_hMainWnd,WM_NEW_SELECTION,&rect,edi
;/* show main-window */
invoke ShowWindow,g_hMainWnd,SW_RESTORE
.endif
.elseif uMsg == WM_MOUSEMOVE
.if g_hWndFrame
;/* update window position (frame) */
fn GetCursorPos,&g_rcFrame.right
fn RtlMoveMemory,&rect,&g_rcFrame,RECT
fn checkRect,&rect
mov ecx,rect.right
mov edx,rect.bottom
sub ecx,rect.left
sub edx,rect.top
invoke SetWindowPos,g_hWndFrame,0,rect.left,rect.top,ecx,edx,SWP_NOZORDER
.endif
.elseif uMsg == WM_PAINT
invoke BeginPaint,hWnd,ADDR ps
mov ecx,ps.rcPaint.right
mov edx,ps.rcPaint.bottom
sub ecx,ps.rcPaint.left
sub edx,ps.rcPaint.top
mov rect.right,ecx
mov rect.bottom,edx
fnx ebx = CreateCompatibleDC,ps.hdc
fnx edi = SelectObject,ebx,rv(CreateCompatibleBitmap,ps.hdc,rect.right,rect.bottom)
fnx hBr = SelectObject,ebx,rv(CreateSolidBrush,COLOR_OVERLAY)
invoke BitBlt,ebx,0,0,rect.right,rect.bottom,ebx,0,0,PATCOPY
fn DeleteObject,rv(SelectObject,ebx,hBr)
fn BitBlt,ps.hdc,ps.rcPaint.left,ps.rcPaint.top,rect.right,rect.bottom,ebx,0,0,SRCCOPY
fn DeleteObject,rv(SelectObject,ebx,edi)
fn DeleteDC,ebx
invoke EndPaint,hWnd,ADDR ps
.else
invoke DefWindowProc,hWnd,uMsg,wParam,lParam
ret
.endif
xor eax,eax
ret
OverlayProc endp
;/* This window is hit-transparent and shows the selection-frame */
FrameProc proc uses ebx esi edi hWnd:HWND,uMsg:UINT,wParam:WPARAM,lParam:LPARAM
LOCAL ps:PAINTSTRUCT
LOCAL hBr:HBRUSH,hPen:HPEN
LOCAL rect:RECT
.if uMsg == WM_DESTROY
.elseif uMsg == WM_CREATE
invoke SetLayeredWindowAttributes,hWnd,COLOR_KEY,128,LWA_COLORKEY OR LWA_ALPHA
.elseif uMsg == WM_PAINT
fn GetClientRect,hWnd,&rect
invoke BeginPaint,hWnd,ADDR ps
fnx ebx = CreateCompatibleDC,ps.hdc
fnx edi = SelectObject,ebx,rv(CreateCompatibleBitmap,ps.hdc,rect.right,rect.bottom)
fnx hBr = SelectObject,ebx,rv(CreateSolidBrush,COLOR_KEY)
invoke BitBlt,ebx,0,0,rect.right,rect.bottom,ebx,0,0,PATCOPY
fnx hPen = SelectObject,ebx,rv(CreatePen,PS_SOLID,FRAME_WIDTH,FRAME_COLOR)
invoke Rectangle,ebx,rect.left,rect.top,rect.right,rect.bottom
fn DeleteObject,rv(SelectObject,ebx,hPen)
fn DeleteObject,rv(SelectObject,ebx,hBr)
fn BitBlt,ps.hdc,0,0,rect.right,rect.bottom,ebx,0,0,SRCCOPY
fn DeleteObject,rv(SelectObject,ebx,edi)
fn DeleteDC,ebx
invoke EndPaint,hWnd,ADDR ps
.else
invoke DefWindowProc,hWnd,uMsg,wParam,lParam
ret
.endif
xor eax,eax
ret
FrameProc endp
end main
Quote from: jj2007 on March 02, 2014, 01:03:17 PMSimilar: A transparent window that draws rectangles using GetWindowDC.
you might describe that more detailed.
Quote from: qWord on March 03, 2014, 05:43:33 AM
Quote from: jj2007 on March 02, 2014, 01:03:17 PMSimilar: A transparent window that draws rectangles using GetWindowDC.
you might describe that more detailed.
Basically, you paint rectangles on a window that doesn't paint its background.
Simple example attached, in plain Masm32 (exe, asm and asc for the proud RichMasm user ;)). Actually, I needed this app for something completely unrelated to this thread, so thanks to the OP for pushing me a little bit :t
EDIT: Version 2 leaves W=nnn, H=nnn on top right corner of each rectangle.
Quote from: jj2007 on March 03, 2014, 07:00:06 PMBasically, you paint rectangles on a window that doesn't paint its background.
That method does no longer work due to the desktop window manager (vista+), which compose the final image from buffers - the applications no longer draw directly to the screen DC.
Quote from: qWord on March 04, 2014, 12:33:16 AM
Quote from: jj2007 on March 03, 2014, 07:00:06 PMBasically, you paint rectangles on a window that doesn't paint its background.
That method does no longer work due to the desktop window manager (vista+), which compose the final image from buffers - the applications no longer draw directly to the screen DC.
It works perfectly under Win7, provided you are using a "classic" theme. With Aero, you get indeed white rectangles instead of frames.
You need to handle raw input events. RegisterRawInputDevices + GetRawInputData. This is what some games use. Some firewalls might raise alarm regarding this.
1. Take a snapshot of the whole screen
2. Capture the mouse pointer
3. Create a popup window (with on-top state) to cover the screen
4. Bitblt the screenshot to your window
5. Change the pointer shape (crosshair?) to give some user feedback, and allow the user to drag an outline, or whatever else
6. Respond to the click and save the image portion to file
7. Destroy your popup window, and free your resources (bitmaps, DCs, etc)
8. Release the mouse pointer
Easy?
@Tedd: With all due respect, that sounds like a ... klugey solution at best.
In my original post I mentioned how a piece of commercial software I use (Paint Shop Pro) has this functionality built in. Is anyone here familiar with this program? I'm still using their version 7.00, which by now is pretty ancient, but still works fine for me. I'll bet (though I'd have to try it) that it would still work under Vista, perhaps even Windows 7, including the nifty screen-lasso function.
Also, regarding the solution suggested by Dave (I think) earlier, ugh: hadn't figured on having to write a DLL for my little app. I've never written one and frankly don't really have any desire to do so ...
Quote from: NoCforMe on March 25, 2014, 10:04:45 AM.. (Paint Shop Pro) has this functionality built in. Is anyone here familiar with this program? I'm still using their version 7.00, which by now is pretty ancient, but still works fine for me. I'll bet (though I'd have to try it) that it would still work under Vista, perhaps even Windows 7, including the nifty screen-lasso function.
Version 4.18 works fine under Windows 7...
Quote from: NoCforMe on March 25, 2014, 10:04:45 AM
@Tedd: With all due respect, that sounds like a ... klugey solution at best.
In my original post I mentioned how a piece of commercial software I use (Paint Shop Pro) has this functionality built in. Is anyone here familiar with this program? I'm still using their version 7.00, which by now is pretty ancient, but still works fine for me. I'll bet (though I'd have to try it) that it would still work under Vista, perhaps even Windows 7, including the nifty screen-lasso function.
Also, regarding the solution suggested by Dave (I think) earlier, ugh: hadn't figured on having to write a DLL for my little app. I've never written one and frankly don't really have any desire to do so ...
Windows doesn't provide a direct way to do this, and you're trying to copy the contents of other windows - any solution is going to be some kind of kludge. This is the cleanest way I could think to do it.
I have just tried with PSP7 and it works almost the same way minus the intermediate popup window - the capture rectangle is drawn directly on to the screen (xor-ed so that xor-ing again will remove it), with the hope that you won't to interact with any other windows during that time (you still can via the keyboard), and the snapshot is actually taken with the next click. This is a fairly hacky-but-it-works-in-most-cases approach.
For an immediate capture (full-screen, window, static area), you can obviously just take the snapshot directly from the screen, but in the case of capturing a user-drawn rectangle I did suggest taking the snapshot first and then using it on a popup window for a few reasons:
- you're going to be drawing some kind of interface on top of everything else, which shouldn't interfere with any other windows' contents (even in the case of xor-ing simple lines, this leaves artefacts if their window contents change during that time);
- it should avoid problems caused by composition rendering on later windows version (untested whether it would be a problem, but it doesn't hurt either);
- it makes sense to capture what was on the screen when the capture was requested, and not some seconds later after a rectangle has been drawn around the..... oops, it's changed and now I missed it.
Any less kludgey magic solutions welcome.
Tedd is right, doing a BitBlt() on the screen (with or without the calling window) then chop out the bit you want that you mark out with the mouse rectangle. From memory you just BitBlt() the rect area that is marked out with the mouse reading the mouse down then up messages.
Quote from: Tedd on March 26, 2014, 06:12:04 AM
I have just tried with PSP7 and it works almost the same way minus the intermediate popup window - the capture rectangle is drawn directly on to the screen (xor-ed so that xor-ing again will remove it), with the hope that you won't to interact with any other windows during that time (you still can via the keyboard), and the snapshot is actually taken with the next click. This is a fairly hacky-but-it-works-in-most-cases approach.
For an immediate capture (full-screen, window, static area), you can obviously just take the snapshot directly from the screen [...]
Ackshooly, that's
exactly what I want. Take a snapshot of the screen as it is at the time of lassoing, then size an area. No concern about subsequent changes to window contents.
Actually, I don't even want the contents of the screen: I only want to be able to draw a lasso and determine the
size of the lassoed area. Like PSP 7 does, I can indicate the size directly on the screen (I think by creating a cursor that's an image of the size string--
x X y--so no other interface or popup windows needed). This isn't perfect--with my browser (Opera), it left some garbage on the screen during the capture--but it would work well enough for my purposes.
So can you tell me how to do that? I don't know how to access the screen, nor how to conduct mouse operations outside of my client windows. Oh, and the way PSP works, when you capture the screen, the PSP client windows completely disappear.
This might in itself be klugey, but it would satisfy the requirements of my little project.