This is a read-only snapshot of the ComputerCraft forums, taken in April 2020.
nitrogenfingers's profile picture

Double Click Event

Started by nitrogenfingers, 21 May 2015 - 02:51 AM
nitrogenfingers #1
Posted 21 May 2015 - 04:51 AM
I threw together a little script to save me a bit of time, and as I couldn't find an equivalent on the forums I thought I'd share it. It just provides support for double clicking, as a replacement for multiple single-click events. This is a pretty easy task to do in-code with some timers but I thought it'd save me a bit of cumbersome workarounds by changing the event method itself, seeing as that's the outcome of what I'm doing anyway.

The snippet directly overwrites the os.pullEvent function (it doesn't affect pullEventRaw) and adds a timer that will modify an incoming "mouse_click" event into a "mouse_doubleclick" event if it occurs within a customizable interval. After that, all clicks will be reported as mouse_click events until the interval expires. That interval can be customized with the setDoubleClickInterval function; by default it's a quarter of a second. Because this makes a change directly to the event pulling, it retains compatability and functionality with hard-coded event methods like sleep.

Spoiler
--To avoid this being called twice
if _gPullEvent then
	return
end

local _dctimer = nil
local _dcinterval = 0.25
local _captured = false

--Kept non-local, so it can be reset if necessary
_gPullEvent = os.pullEvent


os.pullEvent = function(_type)
  local _event = { _gPullEvent(_type) }
  if _event[1] == "mouse_click" then
	--Weve clicked within our threshold, so we
	--create the doubleclick event
	if _dctimer and not _captured then
	  _event[1] = "mouse_doubleclick"
	  --No consecutive double-clicks.
	  _captured = true
	elseif not _captured then
	  --Prepare for double click
	  _dctimer = os.startTimer(_dcinterval)
	end
	return unpack(_event)
  --Timer has elapsed, so event is not available
  elseif _event[1] == "timer" and _event[2] == _dctimer then
	_dctimer = nil
	_captured = false
  else
	--Event queued as normal
	if _dctimer then _captured = true end
	return unpack(_event)
  end
end

--Sets the length of the interval for a doubleclick
setDoubleClickInterval = function(_val)
  if _val and type(_val) == "number" and
	  _val > 0 then
	_dcinterval = _val
  end
end

--Restores the original pullEvent function.
removeDoubleClick = function()
  os.pullEvent = _gPullEvent
  _gPullEvent = nil
  setDoubleClickInterval = nil
  removeDoubleClick = nil
end

The program should work as an API or directly in a program's source code, but either way by overwriting and changing the pullEvent function, this API will make other programs that rely on mouse events have unusual behaviour, as the double click replaces the existing mouse event. You can solve this problem yourself by creating and queuing the modified event, then returning the old event (so both fire) but this removes a lot of the convenience I wrote the function to solve in the first place.

So my workaround is the removeDoubleClick function, which will restore the old function and do a cleanup. I recommend calling this function at the end of every program that uses the API to make sure it's compatible with everything else on your system.

This post is like 90% warnings on how hacky and awful it is but I've found it a bit of a timesaver so hopefully someone else does too. Please send me any errors, issues or suggested improvements if you decide to use it.
Edited on 21 May 2015 - 04:59 AM
Lyqyd #2
Posted 21 May 2015 - 05:34 AM
Neat! A simple script, overriding exactly the right thing. I like seeing stuff like this and Gopher's ctrlkeys scripts that make it much easier to interpret user input beyond the basic key/char/clicks.
nitrogenfingers #3
Posted 21 May 2015 - 12:51 PM
Thanks :)/> Gopher's ctrlkeys was definitely an inspiration, although the implementation appears very different.
theoriginalbit #4
Posted 21 May 2015 - 12:56 PM
Nice :)/> I do remember throwing together a little demo a long time ago for the suggestions forum when people wanted right and left click on monitors, so I had a double click as a secondary, though it definitely was more of a demo than anything that could be used.

EDIT: Found the post wow, Aug 2013… wow the script was from Jan 2013! And still by far my one of my most viewed scripts on Pastebin!
Edited on 21 May 2015 - 10:59 AM