Selecting an area on the screen with a mouse

I need to allow the user to select an area on the screen and then have my app know the upper left and lower right corners of their selection. Code to then take the screen shot to the clipboard or image file on the desktop would be very helpful too. I’ve seen forum references to TextArea.CharPosAtXY, TextEdit.SelStart and TextEdit.SelLength, shell.Execute “screencapture -i ~/Desktop/Hello.png” but not getting the examples to work.

The user should be able to click on a button to start the process, position the mouse at the upper left, drag to the lower left and release it. The app should then record the upper left and lower right positions as integer X,Y coordinates. It’s really not much different than the Snipping Tool in Windows and Command-Shift-4 on the Mac, but I’m having difficulty getting anything I’ve found on the forum to work in my app. Thanks much!

You get the size of the screen with the Screen object.

You get the coordinates of the mouse relative to the screen with System.MouseX and MouseY.

Access to screencapture with Xojo has been documented by a member at https://forum.xojo.com/8442-snapshot-of-htmlviewer

Problem is the MouseDown / MouseUp events in your app work only for the current window. I have no idea how to trap a selection out of the Xojo running application, somewhere else on the screen.

A possible workaround would be :

  • Capture the whole current screen state with ScreenCapture
  • Present to the user a full screen window showing the screencapture. It should feel to the user as nothing happened, expect now you have mousedown and mouseup to delimit the area to capture. You will need to draw the selection rectangle, though.
  • Come back to the regular window
  • Capture the portion of the picture delimited by the mouse

This works on Mac…

https://forum.xojo.com/10400-how-can-i-execute-command-shift-4-from-a-pushbutton/p1#p74129

… a similar one for windows would be appreciated.

Lennox

Simple enough. I did not realize -i prompted user for a screen area.

Thanks !

PS : For Windows WFS has a screen capture. I did not test it myself, though.

If you need the coordinates here’s a way to do it on mac. When the pushbutton is clicked a new window is made that is fully transparent, fills the screen and on top of most everything. Mousing on this window draws a rect and on mouse up the coordinates are sent back to Window1 for display. Press esc to cancel.

Once you have the coordinates run a Shell for the screenshot :slight_smile:

[code]Window1

//Label1 (sized wide enough for results)

//PushButton1
Sub Action()
dim w As new Window2 //start a new transparent window that will call back
End Sub

Sub userSelectedRect(x As integer, y As integer, w As integer, h As integer)
beep
Label1.Text = Str(x) + ", " + Str(y) + ", " + Str(w) + ", " + Str(h)
End Sub

Window2

Properties: downX, downY, dragX, dragY As Integer

Sub Open()
const cocoa = “Cocoa.framework”
const kCGMaximumWindowLevelKey = 14
declare function NSClassFromString lib cocoa (aClassName as CFStringRef) as Ptr
declare sub setOpaque lib cocoa selector “setOpaque:” (id As integer, b As boolean)
declare function clearColor lib cocoa selector “clearColor” (NSColorClass As Ptr) As Ptr
declare sub setBackgroundColor lib cocoa selector “setBackgroundColor:” _
(NSWindow As integer, backgroundColor As Ptr)
declare sub setIgnoreMouse lib cocoa selector “setIgnoresMouseEvents:” _
(id As integer, ignore As boolean)
declare sub setStyle lib cocoa selector “setStyleMask:” (id As integer, mask As UInt32)
declare sub setLevel lib “Cocoa” selector “setLevel:” (id As integer, newLevel As integer)
declare function CGWindowLevelForKey lib “Cocoa” (key as integer) as integer
dim w As integer = self.Handle

setOpaque(w, false) //set window fully transparent
setBackgroundColor(w, clearColor(NSClassFromString(“NSColor”)))

setIgnoreMouse(w, false) //don’t let mouse fall through

setStyle(w, 0) //hide title bar (maybe unnecessary)

setLevel(w, CGWindowLevelForKey(kCGMaximumWindowLevelKey)) //put above others

Bounds = new REALbasic.Rect(0, 0, Screen(0).Width, Screen(0).Height) //set bounds to fill screen

MouseCursor = System.Cursors.ArrowAllDirections //change cursor

End Sub

Function MouseDown(X As Integer, Y As Integer) As Boolean
downX = X
downY = Y
return true
End Function

Sub MouseDrag(X As Integer, Y As Integer)
dragX = X
dragY = Y
me.Invalidate
End Sub

Sub MouseUp(X As Integer, Y As Integer)
dim x0, y0, x1, y1 As integer
x0 = Min(downX, X)
x1 = Max(downX, X)
y0 = Min(downY, Y)
y1 = Max(downY, Y)

Window1.userSelectedRect(x0, y0, x1 - x0, y1 - y0)

Close

End Sub

Sub Paint(g As Graphics, areas() As REALbasic.Rect)
dim x0, y0, x1, y1 As integer
x0 = Min(downX, dragX)
x1 = Max(downX, dragX)
y0 = Min(downY, dragY)
y1 = Max(downY, dragY)

g.ForeColor = &c000000CC
g.FillRect x0, y0, x1 - x0, y1 - y0

g.ForeColor = &cFFFFFF
g.DrawRect x0, y0, x1 - x0, y1 - y0

End Sub

Function KeyDown(Key As String) As Boolean
if Asc(Key) = 27 then Close
End Function[/code]