# Tool with repeat onKeyDown/Up - workaround

**URL:** <https://forums.sketchup.com/t/tool-with-repeat-onkeydown-up-workaround/124485>\
**Category:** Ruby API\
**Tags:** plane, tools\
**Created:** [May 5, 2020, 5:29pm UTC](https://forums.sketchup.com/t/tool-with-repeat-onkeydown-up-workaround/124485 "2020-05-05T17:29:18Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![rvs1977](https://sea2.discourse-cdn.com/sketchup/user_avatar/forums.sketchup.com/rvs1977/32/15210_2.png) [@rvs1977](https://forums.sketchup.com/u/rvs1977)\
**Post date:** [May 5, 2020, 5:29pm UTC](https://forums.sketchup.com/t/tool-with-repeat-onkeydown-up-workaround/124485/1 "2020-05-05T17:29:18Z")

</div>

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](https://global.discourse-cdn.com/sketchup/original/3X/b/4/b4924cee9f56043104a7a1bee15bdab4d6b31c79.png)

```
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

```

---

<div class="post-metadata">

**Author:** ![DanRathbun](https://sea2.discourse-cdn.com/sketchup/user_avatar/forums.sketchup.com/danrathbun/32/500_2.png) [@DanRathbun](https://forums.sketchup.com/u/DanRathbun)\
**Post date:** [May 5, 2020, 6:08pm UTC](https://forums.sketchup.com/t/tool-with-repeat-onkeydown-up-workaround/124485/2 "2020-05-05T18:08:20Z")

</div>

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.

---

<div class="post-metadata">

**Author:** ![rvs1977](https://sea2.discourse-cdn.com/sketchup/user_avatar/forums.sketchup.com/rvs1977/32/15210_2.png) [@rvs1977](https://forums.sketchup.com/u/rvs1977)\
**Post date:** [May 5, 2020, 6:37pm UTC](https://forums.sketchup.com/t/tool-with-repeat-onkeydown-up-workaround/124485/3 "2020-05-05T18:37:49Z")

</div>

The solution is based on a post.

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

actually I thought I had found the **big trick**

 ![image](https://global.discourse-cdn.com/sketchup/original/3X/7/c/7c75ab0222ae9b19e98b1ec3260fa8ae896146a4.png)

I use Windows 7 and SU17

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

---

<div class="post-metadata">

**Author:** ![DanRathbun](https://sea2.discourse-cdn.com/sketchup/user_avatar/forums.sketchup.com/danrathbun/32/500_2.png) [@DanRathbun](https://forums.sketchup.com/u/DanRathbun)\
**Post date:** [May 5, 2020, 8:40pm UTC](https://forums.sketchup.com/t/tool-with-repeat-onkeydown-up-workaround/124485/4 "2020-05-05T20:40:11Z")

</div>

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](https://github.com/SketchUp/api-issue-tracker/issues) ?  
Take note of [Issue #176](https://github.com/SketchUp/api-issue-tracker/issues/176) regarding the return value from some callbacks.

---

<div class="post-metadata">

**Author:** ![rvs1977](https://sea2.discourse-cdn.com/sketchup/user_avatar/forums.sketchup.com/rvs1977/32/15210_2.png) [@rvs1977](https://forums.sketchup.com/u/rvs1977)\
**Post date:** [May 6, 2020, 1:03pm UTC](https://forums.sketchup.com/t/tool-with-repeat-onkeydown-up-workaround/124485/5 "2020-05-06T13:03:20Z")

</div>

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…
