How to perform LMB click with maxscript?


#1

Hi!

I’m trying to perform a click with the left mouse button, using maxscript, but with no success for now. The task is to select the object under the mouse. Here is the code that I have(it includes some code of denisT and other guys that I found on the net):


 (
 	function SetMousePos x y =
 	(
 		(dotnetClass "Cursor").Position = dotnetObject "System.Drawing.Point" x y
 	)
 		
 	function  MakeParam LoWord HiWord =
 	(
 		bit.or (bit.shift HiWord 16) (bit.and LoWord 0xFFFF)
 	)
 		
 	function LeftMouseButtonClick x y =
 	(
 		WM_LBUTTONDOWN = 0x0201
 		WM_LBUTTONUP 	= 0x0202		
 		MK_LBUTTON = 0x0001
 		
 		stopLoop = false
 		hwnd = undefined
 		for w in (windows.getChildrenHWND #max) where w[4] == "ViewPanel" while stopLoop == false do
 		(
 			hwnd = w[1]
 			stopLoop = true				
 		)
 		hwnd = (windows.getChildrenHWND hwnd)[1][1]		
 			
 		p0 =  MakeParam x y
 		
 		uiaccessor.sendmessage hwnd WM_LBUTTONDOWN MK_LBUTTON p0
 		uiaccessor.sendmessage hwnd WM_LBUTTONUP 0 p0 
 		
 -- 		windows.sendmessage hwnd WM_LBUTTONDOWN MK_LBUTTON 0 
 -- 		windows.sendmessage hwnd WM_LBUTTONUP 0 0 
 	)
 	--
 	rectShape = convertToSplineShape (Rectangle())
 	--	
 	vptDiff = mouse.screenpos - mouse.pos
 	
 	gw.setTransform (matrix3 1)
 	vertScreenPos = gw.wtransPoint (getKnotPoint rectShape 1 1)
 	--
 	posToSetX1 = vptDiff[1] + vertScreenPos[1]
 	posToSetY1 = vptDiff[2] + vertScreenPos[2]
 	--
 	SetMousePos posToSetX1 posToSetY1
 	--
 	LeftMouseButtonClick posToSetX1 posToSetY1
 )
 

The script creates a recganel, converts it to an edhtable spline object, then moves the cursor over the first knot. But the LeftMouseButtonClick fn not works as I want.


#2

you have to use postmessage instead of sendmessage.


#3

Like this:


(
	function SetMousePos x y =
	(
		(dotnetClass "Cursor").Position = dotnetObject "System.Drawing.Point" x y
	)
		
	fn makeParam LoWord HiWord =
	(
		bit.or (bit.shift HiWord 16) (bit.and LoWord 0xFFFF)
	)
		
	function LeftMouseButtonClick x y =
	(
		WM_LBUTTONDOWN = 0x0201
		WM_LBUTTONUP 	= 0x0202		
		MK_LBUTTON = 0x0001
		
		stopLoop = false
		hwnd = undefined
		for w in (windows.getChildrenHWND #max) where w[4] == "ViewPanel" while stopLoop == false do
		(
			hwnd = w[1]
			stopLoop = true				
		)
		hwnd = (windows.getChildrenHWND hwnd)[1][1]		
			
		p0 = makeParam x y
		
		
		windows.postmessage  hwnd WM_LBUTTONDOWN MK_LBUTTON p0
		windows.postmessage  hwnd WM_LBUTTONUP 0 p0 
		
-- 		windows.sendmessage hwnd WM_LBUTTONDOWN MK_LBUTTON 0 
-- 		windows.sendmessage hwnd WM_LBUTTONUP 0 0 
	)
	
	rectShape = convertToSplineShape (Rectangle())
	--	
	vptDiff = mouse.screenpos - mouse.pos
	
	gw.setTransform (matrix3 1)
	vertScreenPos = gw.wtransPoint (getKnotPoint rectShape 1 1)
	--
	posToSetX1 = vptDiff[1] + vertScreenPos[1]
	posToSetY1 = vptDiff[2] + vertScreenPos[2]
	--
	SetMousePos posToSetX1 posToSetY1
	--
	LeftMouseButtonClick posToSetX1 posToSetY1
)

Still not working.


#4

you was picking from wrong place. here is how it should be:

(
	fn makeParam LoWord HiWord =
	(
		bit.or (bit.shift HiWord 16) (bit.and LoWord 0xFFFF)
	)
	fn LeftMouseButtonClick pos =
	(
		WM_LBUTTONDOWN	= 0x0201
		WM_LBUTTONUP 	= 0x0202		
		
		viewHWND = for w in (windows.getChildrenHWND #max) where w[4] == "ViewPanel" do exit with (windows.getChildrenHWND w[1])[1][1]
			
		pp = makeParam (pos.x as integer) (pos.y as integer)
		
		windows.postmessage viewHWND WM_LBUTTONDOWN 0 pp
		windows.postmessage viewHWND WM_LBUTTONUP 0 pp
	)
	
	delete objects
	gc()
	
	sp = convertToSplineShape (circle())
	gw.setTransform (matrix3 1)
	pos = gw.TransPoint (getKnotPoint sp 1 1)
	-- SetMousePos posToSetX1 posToSetY1
	LeftMouseButtonClick pos
)

no reason to move mouse, no reason to pass mouse button id (message tells everything)


#5

Thank you.
I’ve read your code and the LeftMouseClickButton fn is the same as mine(shorter). My hwnd have the same value as your viewHWND, but your function works and mine not.
Then I found that the knot position that I pass to the function is not the world knot position, but shifted. You pass the world knot position and everything works. If I pass the world knot position , like you, my code also work - with the postMessgave as you suggested. Last few days I’ve tested with the world knot position, but not with the postMessage.


(
	function SetMousePos x y =
	(
		(dotnetClass "Cursor").Position = dotnetObject "System.Drawing.Point" x y
	)
		
	function MakeParam LoWord HiWord =
	(
		bit.or (bit.shift HiWord 16) (bit.and LoWord 0xFFFF)
	)
		
	function LeftMouseButtonClick x y =
	(
		WM_LBUTTONDOWN = 0x0201
		WM_LBUTTONUP 	= 0x0202		
		MK_LBUTTON = 0x0001
		
		stopLoop = false
		hwnd = undefined
		for w in (windows.getChildrenHWND #max) where w[4] == "ViewPanel" while stopLoop == false do
		(
			hwnd = w[1]
			stopLoop = true				
		)
		hwnd = (windows.getChildrenHWND hwnd)[1][1]
		p0 = makeParam x y
		
		
		windows.postmessage  hwnd WM_LBUTTONDOWN 0 p0
		windows.postmessage  hwnd WM_LBUTTONUP 0 p0 
		
-- 		windows.sendmessage hwnd WM_LBUTTONDOWN MK_LBUTTON 0 
-- 		windows.sendmessage hwnd WM_LBUTTONUP 0 0 
	)
	
	rectShape = convertToSplineShape (Rectangle())
	--	
	vptDiff = mouse.screenpos - mouse.pos
	
	gw.setTransform (matrix3 1)
	vertScreenPos = gw.transPoint (getKnotPoint rectShape 1 1)
	--
	posToSetX1 = /* vptDiff[1] + */ vertScreenPos[1]
	posToSetY1 = /* vptDiff[2] + */ vertScreenPos[2]
	--
	SetMousePos posToSetX1 posToSetY1
	--
	LeftMouseButtonClick posToSetX1 posToSetY1
)

Thank you again. :slight_smile:


#6

Hi miauu, I’ve tried this with your function (and DenisTs’) and it’s not selecting the object on the first run of the function. Any idea why?

with redraw on LeftMouseButtonClick posToSetX1 posToSetY1


#7

I just tested it. In Prespective viewprot the fn works with no problems. In orthographic viewports the fn works a bit strange. When the ortho viewport is maximized the fn works properly. if the viewport(top, bottom, left, right, front, back) is not maximized - for some vpts the fn works, for other - not.

Create new scene, create only one shape object and use this:

(
	function SetMousePos x y =
	(
		(dotnetClass "Cursor").Position = dotnetObject "System.Drawing.Point" x y
	)
		
	function MakeParam LoWord HiWord =
	(
		bit.or (bit.shift HiWord 16) (bit.and LoWord 0xFFFF)
	)
		
	function LeftMouseButtonClick x y =
	(
		WM_LBUTTONDOWN = 0x0201
		WM_LBUTTONUP 	= 0x0202		
		MK_LBUTTON = 0x0001
		
		stopLoop = false
		hwnd = undefined
		for w in (windows.getChildrenHWND #max) where w[4] == "ViewPanel" while stopLoop == false do
		(
			hwnd = w[1]
			stopLoop = true				
		)
		hwnd = (windows.getChildrenHWND hwnd)[1][1]
		p0 = makeParam x y
		
		
		windows.postmessage  hwnd WM_LBUTTONDOWN 0 p0
		windows.postmessage  hwnd WM_LBUTTONUP 0 p0 
		
-- 		windows.sendmessage hwnd WM_LBUTTONDOWN MK_LBUTTON 0 
-- 		windows.sendmessage hwnd WM_LBUTTONUP 0 0 
	)
	
-- 	rectShape = convertToSplineShape (Rectangle())
	rectShape = objects[1]
	--	
	vptDiff = mouse.screenpos - mouse.pos
	
	gw.setTransform (matrix3 1)
	vertScreenPos = gw.transPoint (getKnotPoint rectShape 1 1)
	--
	posToSetX1 = /* vptDiff[1] + */ vertScreenPos[1]
	posToSetY1 = /* vptDiff[2] + */ vertScreenPos[2]
	--
	SetMousePos posToSetX1 posToSetY1
	--
	LeftMouseButtonClick posToSetX1 posToSetY1
)

#8

That code was missing the convertToSplineShape bit so it errored out.

It seems to work now as expected when I created a fresh scene but it wasn’t earlier. I’ve tweaked the original code a bit to cater for more mouse clicks.

-- Original thread: https://forums.cgsociety.org/t/how-to-perform-lmb-click-with-maxscript/1745770/4?u=treedwannab
-- MS mouse help:   https://docs.microsoft.com/en-us/windows/win32/inputdev/mouse-input

(

  fn makeParam LoWord HiWord = (
    bit.or (bit.shift HiWord 16) (bit.and LoWord 0xFFFF)
    )

  -- mouseButtonClick function - Default is a single left click.
  fn mouseButtonClick pos mouseAction:#WM_LBUTTON = (

    case of (
      ( mouseAction == #WM_LBUTTON ):       ( mouseMsg = [0x0201,0x0202] )
      ( mouseAction == #WM_MBUTTON ):       ( mouseMsg = [0x0207,0x0208] )
      ( mouseAction == #WM_RBUTTON ):       ( mouseMsg = [0x0204,0x0205] )
      ( mouseAction == #WM_XBUTTON ):       ( mouseMsg = [0x020B,0x020C] )
      ( mouseAction == #WM_LBUTTONDBLCLK ): ( mouseMsg = [0x0203,0]      )
      ( mouseAction == #WM_MBUTTONDBLCLK ): ( mouseMsg = [0x0209,0]      )
      ( mouseAction == #WM_RBUTTONDBLCLK ): ( mouseMsg = [0x0206,0]      )
      ( mouseAction == #WM_XBUTTONDBLCLK ): ( mouseMsg = [0x020D,0]      )
      ( default ):                          ( mouseMsg = [0x0201,0x0202] )
      )

    viewHWND = for w in (windows.getChildrenHWND #max) where w[4] == "ViewPanel" do exit with (windows.getChildrenHWND w[1])[1][1]

    pp = makeParam (pos.x as integer) (pos.y as integer)

    if mouseMsg.x > 0 do windows.postmessage viewHWND mouseMsg.x 0 pp
    if mouseMsg.y > 0 do windows.postmessage viewHWND mouseMsg.y 0 pp

    )

  gc()

  rectShape = convertToSplineShape (Rectangle())
  vptDiff = mouse.screenpos - mouse.pos

  gw.setTransform (matrix3 1)
  vertScreenPos = gw.transPoint (getKnotPoint rectShape 1 1)

  posToSetX1 = /* vptDiff[1] + */ vertScreenPos[1]
  posToSetY1 = /* vptDiff[2] + */ vertScreenPos[2]

  SetMousePos = [posToSetX1,posToSetY1]

  with redraw on mouseButtonClick SetMousePos mouseAction:#WM_LBUTTON

  )