isKeyDown command returns false even when you're holding down the key in question

You can write your topic however you want, but you need to answer these questions:

  1. What do you want to achieve? Keep it simple and clear!

I’m trying to make a Map GUI that allows you to scale its contents up and down and horizontally scroll by using a combination of UserInputServices’ PointerAction Method (basically an inputBegan method specifically for mouse wheels and trackpads) and isKeyDown.

The TL;DR of how the code works is that it activates a PointerAction when the mouse enters the map frame, then checks what keys are being held down when they scroll and perform their corresponding action. If you want the actual code line-for-line or if you want a more lengthy explanation, the code breakdown is below:

Code Breakdown

First, let me give you the global variables and explorer path of everything so you can reference them for context:

Variables
local resizeFrame = script.Parent
-- ^^ The content frame that all the map's content is stored in (for proper scaling)
local mapFrame = resizeFrame.Parent
 -- ^^ The ScrollingFrame that holds everything map-related
local inputService = game:GetService("UserInputService") 
-- ^^ UserInputService for PointedAction and isKeyDown
local scrollConnect
-- ^^ Houses the event for a mouse entering the map so it can be disconnected later
local scrollSensitivity = 10
 -- ^^ a multiplier applied to the detected scroll wheel/pan/pinch so it doesn't ...
--... take ages to pan/scale the map
GUI Directory

Now, onto the explanation:
This is pretty simple, so this won’t take long. First, I prepare simple logic that initiates the scaling/panning logic (transformFrame) when the user’s mouse enters the map GUI, then disconnects everything once it leaves. Not sure if I have to do this, but it’s better to be safe than sorry

resizeFrame.MouseEnter:Connect(function() 
	scrollConnect = inputService.PointerAction:Connect(transformFrame)
end)
resizeFrame.MouseLeave:Connect(function()
	scrollConnect:Disconnect()
end)

Inside transformFrame, it starts by using :isKeyDown to check if the control or shift keys were pressed when it was activated. The zoom feature is bonded to control, while the horizontal scroll is bonded to shift.

local function transformFrame(wheel:number, pan:Vector2, pinch:number, isGUI:boolean)
	local isZooming = inputService:IsKeyDown(Enum.KeyCode.RightShift) or inputService:IsKeyDown(Enum.KeyCode.LeftShift)
	local isPanning = inputService:IsKeyDown(Enum.KeyCode.RightControl) or inputService:IsKeyDown(Enum.KeyCode.LeftControl) 

Then, it performs a series of checks to decide what it will do next:

  1. If there’s no pinch, pan, and neither the zoom or pan keys are being held down, it does nothing because ScrollingFrames can already handle vertical scrolling by its lonesome.
if not isPanning and not isZooming or pan.X ~= 0 or pan.Y ~= 0 then
		warn("Vertically scrolling!")
		return
	end
  1. At this point, we’ve already verified that the user is trying to horizontally scroll, so I have to disable manual scrolling so roblox doesn’t automatically vertically scroll for me
    • mapFrame.ScrollingEnabled = false
  2. There also has to be another check to make sure that the zoom and pan keys aren’t being held at the same time
	if isPanning and isZooming then
		warn("You can't pan and zoom at the same time!")
		mapFrame.ScrollingEnabled = true
		return
  1. Finally, it does the logic on whether to zoom or scroll:
  • If the user is holding ctrl or is actively pinching the mapGUI, the map zooms out
	elseif isZooming or pinch ~= 0 then
		scaleMapFrame(wheel, pinch)
  • If the user is holding shift or is actively horizontally panning the screen, then the map horizontally pans
	elseif isPanning or pan.X ~= 0 then
		if pan.X ~= 0 then	
			return horizontalMapFrameMove(pan.X)
		end
		horizontalMapFrameMove(wheel)
	end	
  1. Then when everything’s said and done, scrolling gets reenabled
    • mapFrame.ScrollingEnabled = true

And that’s it! I’m sure there are more efficient ways of doing things, but that’s just how I chose to do it. I’ll probably improve the logic later because even as I write this, I see a few parts that could cause bugs later down the line.

  1. What is the issue? Include screenshots / videos if possible!
    Basically, the isKeyDown methods to check if a certain key is being pressed always returns false regardless of if its being held down or not. No idea what’s happening because the PointerAction does get triggered and the function inside of it does indeed run, but no matter what happens, isKeyDown always returns false no matter what. Below is proof of this weird bug happening:
Video of Issue in Action

https://youtu.be/gVnmVgmBbig

  1. What solutions have you tried so far? Did you look for solutions on the Developer Hub?
    I could disregard isKeyDown and manually use inputBegan events to track if the key is being held or not, but I’m hoping that I don’t have to do anything like that and can use the Roblox tools bestowed upon me by the great devs in the sky.

If anyone could help me with this, I’d be static. So far, I’ve had a 0% response rate on any of the 3 topics I’ve opened, so it would make my day if anyone even attempted to help me instead of clicking off. But regardless of if you help me or not, thanks for reading this all the way through :slight_smile:

Updates/Fix Attempts:

  1. Moving isKeyDown to be inside of a heartbeat loop, in case the PointerAction event didn’t trigger them frequently enough to see the key presses
Changes made to the code
  1. Added 4 new global variables:
    • RunService
    • isZooming (the zoom key’s isKeyDown)
    • isPanning (the horizontal pan’s isKeyDown)
    • heldKeyHeartbeat (the HeartBeat connect used to disconnect the service when not hovering over the map GUI (for optimization purposes))
local resizeFrame = script.Parent
local mapFrame = resizeFrame.Parent
local inputService = game:GetService("UserInputService")
local runService = game:GetService("RunService") <-- new!
local scrollSensitivity = 10
local scrollConnect
local heldKeyHeartbeat <-- new!

local isZooming = nil <-- new!
local isPanning = nil <-- new!
  1. Changed the resizeFrame’s MouseEnter connect to also start a heartbeat connect that constantly checks for the shift and control keys
resizeFrame.MouseEnter:Connect(function() 
	scrollConnect = inputService.PointerAction:Connect(transformFrame)
	-- vvv new stuff below... vvv
	heldKeyHeartbeat = runService.Heartbeat:Connect(function()
		isZooming = inputService:IsKeyDown(Enum.KeyCode.RightShift) or inputService:IsKeyDown(Enum.KeyCode.LeftShift)
		isPanning = inputService:IsKeyDown(Enum.KeyCode.RightControl) or inputService:IsKeyDown(Enum.KeyCode.LeftControl) 
	end)
end)
  1. Changed the resizeFrame’s MouseLeave connect to also disconnect the heartbeat connect so it doesn’t slow down the game while it’s not being used
resizeFrame.MouseLeave:Connect(function()
	scrollConnect:Disconnect()
	heldKeyHeartbeat:Disconnect() <-- new!
end)
Results Showcase (failed)

https://youtu.be/b2nwA_j7A5Q


I ended up having to reinstall studio, but at least everything works now! This is 14 days later because I forgot about this thread. Sorry…

Edit Log

Edit #1: 3:56AM MST, 7/16/24
  • Added “Updates/Fix Attempts” Page
  • Added first fix attempt
  • Fixed typo in “What is the issue?”
  • Get rid of the ... when introducing the code breakdown’s transformFrame function (sorry for the confusion!)
11 Likes

That’s quite the odd issue, a possible cause I can think of is the transformFrame function isn’t being called frequently enough to accurately detect the key’s state, since when I use IsKeyDown, I usually do so within a loop, and haven’t yet experienced a similar issue, so hopefully doing so yourself might fix the issue :slight_smile::+1:


Can confirm that calling the function within a loop works ok (Tested using a LocalScript inside of StarterPlayerScripts):

local inputService = game:GetService("UserInputService")

local isZooming, isPanning

local function transformFrame()
	isZooming = inputService:IsKeyDown(Enum.KeyCode.RightShift) or inputService:IsKeyDown(Enum.KeyCode.LeftShift)
	isPanning = inputService:IsKeyDown(Enum.KeyCode.RightControl) or inputService:IsKeyDown(Enum.KeyCode.LeftControl)
end

game:GetService("RunService").Heartbeat:Connect(function()
	transformFrame()
	print(isZooming, isPanning)
end)
6 Likes

Sorry for responding late, I was working on other parts of my game and I didn’t think to check the devforum until now. But to respond to your idea:

I’m a little confused by what you mean by this. Like the function has to be called in a loop of some sort (like a while, for, heartbeat, or renderStepped) to work? Frequency-wise, the PointerAction event is activated very rapidly-- like .5 of a mouse scroll kind of frequent (or whatever unit of measurement they use for the mouse wheel). In the “Video of Issue in Action” tab, you can see in the terminal that the returned mouse wheel increments are not only tiny (usually never above 1), but they also happen pretty rapidly, with at least 10 events being fired every second it detects you scrolling.

But your idea is still worth a try-- I’ll make the 2 button check global variables and update them on heartbeat and get back to you on what happens

4 Likes

Come to think of it, since isZooming and isPanning are declared as local variables to the transformFrame function’s scope, the issue could also be happening due to something preventing the function from returning the correct values, since the ... imply that the function contains more code than shown

If the function is returning nil, nil, it will be equivalent to it returning false, false, since nil is considered equivalent to false in boolean operations

3 Likes

Yeah, sorry about that-- it’s kinda misleading. I put the ... there because I wanted to signify that there was more to the function, but the “more” part was what I talked about later on in the code breakdown. The only things I’ve committed were all of my haphazard print statements. Sorry for not being consistent with the ...s and throwing you off :sweat_smile:

As for your suggestion, I just tried it and the results were more of the same: https://youtu.be/b2nwA_j7A5Q
I’ll update the main post soon with this URL and the parts of my code that I changed for this fix attempt. Seriously though-- thanks for replying. I think you’re literally the first person who has ever responded to my support topics and I’m very grateful for that

6 Likes

What happens if you add this right after you set isZooming and isPanning (at line 64 according to the video):

print(`Debug | isZooming: {isZooming} | isPanning: {isPanning}`)

If the values stay false, then you might be experiencing some kind of bug, or there’s also the possibility that it might be an issue with your keyboard, although unlikely since you are checking 4 different keys

3 Likes

Still no dice. But I had no clue you could do Python-style curly string concatenation in Lua! That’ll make debugging easier than having to separate everything with commas.

Video (this time it's small enough to upload directly)

4 Likes

Can you try this code and let me know what it outputs? Running this on my end (even over what seems like frames and scrolling frames) gives the expected results and I’m trying to see whether it is some weird interaction gui elements.

--!strict

local RunService = game:GetService("RunService")
local UserInputService = game:GetService("UserInputService")

local function isZoomingPanning(): (boolean, boolean)
	local isZooming: boolean = UserInputService:IsKeyDown(Enum.KeyCode.LeftShift) or UserInputService:IsKeyDown(Enum.KeyCode.RightShift)
	local isPanning: boolean = UserInputService:IsKeyDown(Enum.KeyCode.LeftControl) or UserInputService:IsKeyDown(Enum.KeyCode.RightControl)
	
	return isZooming, isPanning
end

RunService.Heartbeat:Connect(function(): ()
	print(isZoomingPanning())
end)
3 Likes

Yep, here you go:

Your Code (Ran off the same localScript as the last one, but I replaced my code with yours)

2 Likes

I think I found a possible solution to the problem, although it does require using InputBegan and InputEnded:

local inputService = game:GetService("UserInputService")

local isZooming, isPanning

local function checkKeys()
	isZooming = inputService:IsKeyDown(Enum.KeyCode.LeftShift) or inputService:IsKeyDown(Enum.KeyCode.RightShift)
	isPanning = inputService:IsKeyDown(Enum.KeyCode.LeftControl) or inputService:IsKeyDown(Enum.KeyCode.RightControl)
end

inputService.PointerAction:Connect(function()
	print(isZooming, isPanning)
end)

inputService.InputBegan:Connect(function(_, gameProcessedEvent)
	if gameProcessedEvent then return end

	checkKeys()
end)

inputService.InputEnded:Connect(function(_, gameProcessedEvent)
	if gameProcessedEvent then return end

	checkKeys()
end)

From testing, it seems as though checking the keys within the PointerAction event alone kept resulting in the output being false, while checking the keys externally gave the desired outcome. This could mean that the PointerAction event fires in a similar way that InputBegan does, which means that it’s unable to detect when a key stops being pressed

3 Likes

And you’re pressing Ctrl/Shift in this video?

It seems like a weird bug on your end. Restart studio and see if that fixes the issue. Also worth trying in a live game if your copy of studio is somehow broken.

Edit: Also check your plugins. In studio, if a plugin has a registered studio shortcut, it will completely sink that input. A plugin might have set a shortcut to your Ctrl/Shift keybinds.

1 Like

whoops :man_facepalming:. In my defence, it’s currently 4AM on my end lol. My bad, but it’s still more of the same.

New video with me ACTUALLY pressing shift/ctrl

1 Like

Read edit. Go to File -> Advanced -> Customize Shortcuts... and in the search box, search both Ctrl and Shift.

Under the Shortcut column, if you see a shortcut that is just containing Ctrl or Shift alone, studio will sink those inputs. This wont apply on a live game.

If you don’t see a shortcut just containing those 2 keys, restart or reinstall studio (or try with no plugins running) and see if it has the same behavior.

2 Likes

Out of curiosity, try changing the keys to something else, like W and S instead of LeftShift and RightShift, and A and D instead of LeftControl/RightControl

1 Like

Sorry for the delay-- My computer froze so bad I had to restart it. I had too many apps running at once in the background and it broke the camel’s back. Anyway to respond to yours, I think I need to reinstall studio or something because I just tried both of your suggestions from before and it’s still returning false

A la video

https://youtu.be/i7A8J5aoqBQ

Then for you, I navigated to those places you and I don’t think I have anything set to just shift or control alone. I got studio about 2ish weeks ago, so I never even knew this existed until now. Just in case I accidentally set/missed something, I just screenshotted the results of each search:

Shift Shortcuts

Control Shortcuts

What happens if you try the script I gave you (or the scripts that @OniiSamaUwU gave you, since they should work as well) in a new baseplate? If it works as expected, then it means the issue lies somewhere within the full code. Since you mentioned that it’s currently 4AM (now 5AM, since that message was an hour ago), I recommend taking a break and reviewing or rewriting the script afterwards if the test above works, you’d be surprised as to how much it helps to take breaks in-order to find bugs that are hidden within code :slight_smile::+1:

Yeah, I’m feeling pretty sluggish right now. I’ll take a power nap for a few hours, then try the code on a different baseplate and see what happens. Hopefully, it is something as simple as something else in my spaghetti code causing this weirdness. I have other mouse-related user input things in my game that could potentially be interfering with this one (namely a ray tracer that fires a beam wherever the mouse is every rendered step), so maybe that’s the issue and I don’t have a cursed copy of Studio or anything like that lol. Thanks to both of you guys for helping me out with this so far, and I’ll hopefully talk to you guys again in a bit

2 Likes

So I fell asleep, and I slept straight through my 3 hour timer to wake myself up and now it’s been 12 hours :skull:. I didn’t think I was that tired lol. But regardless, this is what happened when I did it in a new baseplate: https://youtu.be/7VjbW4nG-ps

At this point I might as well reinstall studio because I genuinely don’t know what to try next

1 Like
  1. The image you sent with the shortcuts, you’ve scrolled down and didn’t find any keybind with just Shift or Ctrl right?
  2. Have you tried changing the keys like @JohhnyLegoKing said to something like WASD and see if it’s just a Shift/Ctrl issue?
  3. Have you tried testing it in a live game? You can press F9, go to the menu, or type in /console to open the developer console.

It could unfortunately also be something outside of studio. Try closing any apps that are not essential to running your OS.