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

Mouse and keyboard input simultaneously

Started by nolongerexistant, 23 June 2013 - 01:48 PM
nolongerexistant #1
Posted 23 June 2013 - 03:48 PM
Is it possible to check for mouse clicks and handle keyboard input at the same time?
Let's say I have this code:

print("Type something")
input = read()

while true do
event = {os.pullEvent()}

if event[1] == "mouse_click" then
  print("Mouse click")
end
end

How would I check for mouse clicks while it's waiting for the user to type something?
Engineer #2
Posted 23 June 2013 - 04:02 PM
Of course, the only thing that makes it complex is that you have to write your own read function. This is very, very primitive:

local str = ""

while true do
	local event = { os.pullEvent() }
	if event[1] == "mouse_click" then
		-- Do stuff with your mouse
	elseif event[1] == "char" then
		str = str .. event[2]
	end
end

But like I said, you can take this to the next level and make it super complex if you really want. Only Im not doing that for you :P/>
Grim Reaper #3
Posted 23 June 2013 - 04:38 PM
Engineer gave a great example of how you might do what you're asking for.

Here's a similar way, but using coroutines:


local function mouseClickHandler (eventName, clickType, xClickPos, yClickPos)
	local currentCursorPos = { term.getCursorPos() }

	term.setCursorPos (1, currentCursorPos[2] + 1)
	term.write ("Mouse click at: (" .. currentCursorPos[1] .. ", " .. currentCursorPos[2] .. ')')
        term.setCursorPos (unpack (currentCursorPos))
end

local function modifiedRead()
	local readCoroutine = coroutine.create (read)
	coroutine.resume (readCoroutine)

	local mouseClickHandlerCoroutine = coroutine.create (mouseClickHandler)

	while coroutine.status (readCoroutine) ~= "dead" do
		local eventData = { os.pullEvent() }

		if eventData[1] == "mouse_click" then
			coroutine.resume (mouseClickHandler, unpack (eventData))
		else
			coroutine.resume (readCoroutine, unpack (eventData))
		end
	end
end
nolongerexistant #4
Posted 23 June 2013 - 05:22 PM
Of course, the only thing that makes it complex is that you have to write your own read function. This is very, very primitive:

-snip-

But like I said, you can take this to the next level and make it super complex if you really want. Only Im not doing that for you :P/>

Engineer your example works great, that's the second time tonight :P/>

Engineer gave a great example of how you might do what you're asking for.

Here's a similar way, but using coroutines:

-snip-

Is there an advantage on using coroutines here? All I can think of is that you can actually click and type at the same time
MysticT #5
Posted 23 June 2013 - 06:47 PM
Why would you write a coroutine manager when you have the parallel api? ;)/>

local input

local function getInput()
  print("Type something:")
  input = read()
end

local function getMouseInput()
  while true do
    local evt, btn, x, y = os.pullEvent("mouse_click")
    -- Handle the mouse click here
  end
end

parallel.waitForAny(getInput, getMouseInput)
nolongerexistant #6
Posted 24 June 2013 - 01:46 PM
Why would you write a coroutine manager when you have the parallel api? ;)/>

-snip-

If I use your method, and I click something that clears the screen, it still waits for an input. Is there way to stop that?
Engineer #7
Posted 24 June 2013 - 01:54 PM
If I use your method, and I click something that clears the screen, it still waits for an input. Is there way to stop that?

Then you must have your own read function that checks continueusly if a boolean is true. If that is true it will break that loop it is in
nolongerexistant #8
Posted 24 June 2013 - 01:59 PM
If I use your method, and I click something that clears the screen, it still waits for an input. Is there way to stop that?

Then you must have your own read function that checks continueusly if a boolean is true. If that is true it will break that loop it is in

That'll work :P/>
MysticT #9
Posted 24 June 2013 - 03:03 PM
The parallel.waitForAny call should return when one of the functions ends. So, you just have to make the mouse input function end and it will end the other one too. Example:

local input

local function getInput()
  print("Type something:")
  input = read()
end

local function getMouseInput()
  while true do
    local evt, btn, x, y = os.pullEvent("mouse_click")
    break -- stop the loop when we get a mouse click
  end
end

parallel.waitForAny(getInput, getMouseInput)

term.clear()
term.setCursorPos(1, 1)
if input then
  print("Your input: ", input)
else
  print("You clicked the screen!")
end

If this is not what you need, please explain what you are trying to do, so we can help.
nolongerexistant #10
Posted 24 June 2013 - 05:38 PM
The parallel.waitForAny call should return when one of the functions ends. So, you just have to make the mouse input function end and it will end the other one too. Example:

-snip-

If this is not what you need, please explain what you are trying to do, so we can help.

Your method combined with a custom read function and os.queueEvent() worked mostly fine, just when I clicked something, it executed the command from the click before it ended the keyboard input loop, causing buttons on the next screen to not-respond for some reason. I guess becouse there were multiple os.pullEvent()'s running

But i've just found that this method works perfect:
Spoiler

local data = {}
function main()
term.clear()
term.setCursorPos(1,1)
data[1] = 1
data[2] = 1
data[3] = ms

parallel.waitForAny(handleMouse, handleInput)

data[1] = 2
data[2] = 1
data[3] = ms

handleMouse()
end
function handleInput()
term.write("Input: ")
  local inp = read()

if inp == "yes" then
  kb()
end
end
function handleMouse()
while true do
  local event = {os.pullEvent()}

  if event[1] == "mouse_click" then
   for k, v in ipairs(data) do
	if event[3] == data[1] and event[4] == data[2] then
	 data[3]()
	 return
	end
   end
  end
end
end
function ms()
print("Mouse got here")
end
function kb()
print("Keyboard got here")
end
main()

It's pretty much the same as your function but i've used return instead of break since the wiki states "stops when any of them returns."
theoriginalbit #11
Posted 25 June 2013 - 12:44 AM
your code will error after you restart your computer. Move your functions above the parallel call to fix this future problem.
nolongerexistant #12
Posted 25 June 2013 - 05:10 AM
your code will error after you restart your computer. Move your functions above the parallel call to fix this future problem.

Thanks TOB
theoriginalbit #13
Posted 25 June 2013 - 09:44 AM
Thanks TOB
No problems :)/> as always here to help…

Also, just a side note, if you want to shorten either BIT or TOBIT. I'd prefer former over latter. :)/>