Tool with repeat onKeyDown/Up - workaround

Hi
In Sketchup::Tool the “repeat” variable don’t work in def onKeyDown (key, repeat, flags, view) when the key is hold down.

After some research I found out (with help from a Dan Rathbun post) a way to work around the problem. I have tried to make a simple tool class to illustrate. If you push up or down arrow the size of the plane change

The code can be copy/pasted into the console

image

module RS_2020; end
module RS_2020::RS_TEST_SITE 

class MyKeyStateClass

def initialize(getplanetool)
	@getplanetool = getplanetool
end

def rsKeyDownState(keystatedown, key, view)
	
	if keystatedown
		@id = UI.start_timer(0.01, true) { 
			@getplanetool.rs_plane_zoom(key, view)
		}

	else 
		UI.stop_timer(@id)	
	end

end
end # class MyTestClass(keystate)

class GetPlaneTool
	def initialize(model)

		@keystateclass = MyKeyStateClass.new(self)

		@model = model

		@main_cplane_group = Sketchup.active_model.entities.add_group()
		@yv_group = @main_cplane_group.entities.add_group()
		
		@p_len_x = 50 # plane length x
		@p_len_y = 50 # plane length y

		@pt0 = [-@p_len_x,-@p_len_y ,0]
		@pt1 = [ @p_len_x,-@p_len_y ,0]
		@pt2 = [ @p_len_x, @p_len_y,0]
		@pt3 = [-@p_len_x, @p_len_y,0]
		@pt4 = [0,0,0]
		@pt5 = [0,0,@p_len_y/4]

		stipple = "."
		@cline1 = @yv_group.entities.add_cline(@pt0, @pt1, stipple)
		@cline2 = @yv_group.entities.add_cline(@pt1, @pt2, stipple)
		@cline3 = @yv_group.entities.add_cline(@pt2, @pt3, stipple)
		@cline4 = @yv_group.entities.add_cline(@pt3, @pt0, stipple)
		@cline5 = @yv_group.entities.add_cline(@pt0, @pt2, stipple)
		@cline6 = @yv_group.entities.add_cline(@pt1, @pt3, stipple)
		@cline7 = @yv_group.entities.add_cline(@pt4, @pt5, stipple)

	end # initialize()

	def rs_plane_zoom(key, view)

		@cline1.erase!
		@cline2.erase!
		@cline3.erase!
		@cline4.erase!
		@cline5.erase!
		@cline6.erase!
		@cline7.erase!

		scale_factor = view.pixels_to_model(10, [100,0,0]) * 2

		if (key == 38) # key up

			@p_len_x = @p_len_x + scale_factor # plane length x
			@p_len_y = @p_len_y + scale_factor # plane length y

			@pt0 = [-@p_len_x,-@p_len_y ,0]
			@pt1 = [ @p_len_x,-@p_len_y ,0]
			@pt2 = [ @p_len_x, @p_len_y,0]
			@pt3 = [-@p_len_x, @p_len_y,0]
			@pt4 = [0,0,0]
			@pt5 = [0,0,@p_len_y/4]

	  	end # if (key == 38)

	  	if (key == 40) # key down

			@p_len_x > 5 ? (@p_len_x = @p_len_x - scale_factor) : @p_len_x = 5 # plane length x
			@p_len_y > 5 ? (@p_len_y = @p_len_y - scale_factor) : @p_len_y = 5 # plane length y

			@pt0 = [-@p_len_x,-@p_len_y ,0]
			@pt1 = [ @p_len_x,-@p_len_y ,0]
			@pt2 = [ @p_len_x, @p_len_y,0]
			@pt3 = [-@p_len_x, @p_len_y,0]
			@pt4 = [0,0,0]
			@pt5 = [0,0,@p_len_y/4]

		end # if (key == 40)

	    stipple = "."
	  	@cline1 = @yv_group.entities.add_cline(@pt0, @pt1, stipple)
	  	@cline2 = @yv_group.entities.add_cline(@pt1, @pt2, stipple)
	  	@cline3 = @yv_group.entities.add_cline(@pt2, @pt3, stipple)
	  	@cline4 = @yv_group.entities.add_cline(@pt3, @pt0, stipple)
	  	@cline5 = @yv_group.entities.add_cline(@pt0, @pt2, stipple)
	  	@cline6 = @yv_group.entities.add_cline(@pt1, @pt3, stipple)
	  	@cline7 = @yv_group.entities.add_cline(@pt4, @pt5, stipple)

	end # def rs_plane_zoom

	def onKeyUp(key, repeat, flags, view)
		if (key == 38) # key up
			@keystateclass.rsKeyDownState(false, key, view)
		end

		if (key == 40) # key down
	  		@keystateclass.rsKeyDownState(false, key, view)
	  	end # if (key == 40)

	end # onKeyUp

	def onKeyDown(key, repeat, flags, view)
	  if (key == 38) # key up
	  	@keystateclass.rsKeyDownState(true, key, view)
	  end

	  if (key == 40) # key down
	  	@keystateclass.rsKeyDownState(true, key, view)
	  end 

	end # def onKeyUp

	def activate
	# puts 'Your tool has been activated.'
	end # def activate


	def onMouseMove(flags, x, y, view)
		
		@yv_group.hidden = true
		ph = view.pick_helper
		ph.do_pick(x, y)
		face = ph.picked_face
		plane = [0,0,1]

		

		if face.is_a?Sketchup::Face
			# puts face.plane
			plane = face.plane
			Sketchup.status_text = "Plane - (A: " + face.plane[0].to_s + "), (B:" + face.plane[1].to_s + "), (C:" + face.plane[2].to_s + "), (D:" + face.plane[3].to_s + ")"
		end

		ip = Sketchup::InputPoint.new
		ip.pick view, x,y
		ip = ip.position 

		point = Geom::Point3d.new ip 
		vector = Geom::Vector3d.new(plane[0], plane[1], plane[2])
		angle = 45.degrees
		new_transform = Geom::Transformation.new point, vector
		response = @yv_group.transformation = new_transform 
		@yv_group.visible = true

		model = Sketchup.active_model
		view = model.active_view
		refreshed_view = view.refresh

	end # def onMouseMove(flags, x, y, view)

	def onLButtonDown(flags, x, y, view)
	  		 
	  	ph = view.pick_helper
		ph.do_pick(x, y)
		face = ph.picked_face

		ip = view.inputpoint x,y
		point = ip.position

		plane = [0,0,1]
		if face.is_a?Sketchup::Face

			plane = face.plane
			Sketchup.status_text = face.plane

			@model.tools.pop_tool
			
		end		  
	end # def onLButtonDown(flags, x, y, view)

	def resume(view)
	  # puts "resume: view = #{view}"
	end

	def suspend(view)
		# puts "suspend: view = #{view}"
	end # def suspend(view)
end # class GetPlaneTool

	SKETCHUP_CONSOLE.show
	SKETCHUP_CONSOLE.clear
	puts "Use Up or Down key to change size of plane"

	# *** Create sphere start ***
	model = Sketchup.active_model
	entities = model.active_entities

	centerpoint = Geom::Point3d.new
	vector = Geom::Vector3d.new 0,0,1
	vector2 = vector.normalize!
	edges = entities.add_circle centerpoint, vector2, 100
	
	face = entities.add_face(edges)

	centerpoint = Geom::Point3d.new
	vector = Geom::Vector3d.new 1,0,0
	vector2 = vector.normalize!
	edges = entities.add_circle centerpoint, vector2, 5
	face.followme(edges)
	# *** Create sphere end ***
		
	model = Sketchup.active_model
	tool = GetPlaneTool.new(model)
	model.tools.push_tool(tool)


end #module RS_2020::RS_TEST_SITE

Why use a separate class instance to control a boolean flag ?
Why not just keep the “keystate” within the tool instance itself ?

Basically you are just coding a state for when the key goes down and then back up again, instead of relying upon the repeat parameter. I’d think it will be less confusing if all the functionality is within the Tool class instance itself.

The solution is based on a post.

https://sketchucation.com/forums/viewtopic.php?f=180&t=24327

actually I thought I had found the big trick

I use Windows 7 and SU17

And you are right, it would be much easier if the repeat variable worked

Wow … 10 years ago. I was proposing then to try a subthread which does not really work well in embedded Ruby. Instead you used a C++ timer block (from the API’s UI.start_timer method.)

But it’s clear in that old post I was proposing that the tool instance itself have a keydown state instance variable.

Anyway, I don’t see the benefit of the extra class just to start up a timer. Might as well just do it within the tool itself.


Over the years there have been reports of issues with the repeat flag.

Did you also check the API Issue Tracker ?
Take note of Issue #176 regarding the return value from some callbacks.

Well I think the solution is a bit messy too. But it works for my purpose… And Im not sure how to do it the way you explain.

btw, thanks alot for the help…