Laggy Keyboard Recorder?

Hello, i’ve been trying to get this system to work for a while, what it does is that you press a button to start a Keyboard recording, some kind of macro recorder, or just like when you record piano songs on a piano and it plays what you played perfectly.

I am doing this with animations on a rig, it works as some kind of animatronic which i can “program” to move everytime i press and hold a key, technically that but instead of piano keys its animatronic movements.

However, this system is pretty tricky, since it tends to miss out keys sometimes, or be stuck on one movement sometimes for the entire recording.

Heres an example video

As you see, it doesn’t imitate it pretty well. Here’s some of the script:

uis.InputBegan:Connect(function(obj)
	if obj.UserInputType == Enum.UserInputType.Keyboard and playing == true and script.Parent.startrecording.Text ~= "START" then
		for _, typ in pairs(types) do
			if script.Parent.startrecording.Text ~= "START" then
				if (typ[uis:GetStringForKeyCode(obj.KeyCode.Name)] ~= nil and typ[uis:GetStringForKeyCode(obj.KeyCode.Name)] ~= "") or typ[obj.KeyCode.Name] ~= nil then
					timeStarted = time()
				end
			end
		end
	end
end)

uis.InputEnded:Connect(function(obj, gpe)
	if (obj.UserInputType == Enum.UserInputType.Keyboard) and playing == true and script.Parent.startrecording.Text ~= "START" then
		for _, typ in pairs(types) do
			if script.Parent.startrecording.Text ~= "START" then
				if (typ[uis:GetStringForKeyCode(obj.KeyCode.Name)] ~= nil and typ[uis:GetStringForKeyCode(obj.KeyCode.Name)] ~= "") or typ[obj.KeyCode.Name] ~= nil then
					table.insert(keys,{Key = obj.KeyCode.Name, Time = tick()-startTime,HeldDown = time()-timeStarted})
					print("Time key was held: "..(time() - timeStarted).." seconds.")
				end
			end
		end
	end
end)

script.Parent.startrecording.MouseButton1Click:Connect(function()
	if script.Parent.startrecording.Text == "START" then
		startTime = tick()
		playing = true
		local seconds
		coroutine.wrap(function()
			if length ~= nil then
				coroutine.wrap(function()
					if #keys ~= 0 then
						local keysTemp = keys
						for i,v in pairs(keysTemp) do 
							for _, typ in pairs(types) do
								if (typ[uis:GetStringForKeyCode(v.Key)] ~= nil and typ[uis:GetStringForKeyCode(v.Key)] ~= "") or typ[v.Key] ~= nil then
									if i == 1 then
										script.Played.AnimationId = typ[v.Key][1]
										pauseableWait(v.Time)
										coroutine.wrap(function()
											local animTrack = bot.AnimationController.Animator:LoadAnimation(script.Played)
											animTrack.Priority = Enum.AnimationPriority.Action
											animTrack:Play(typ[v.Key][2])
											animTrack.Looped = true
											print(v.Key.." played after "..v.Time.." seconds.")
											pauseableWait(v.HeldDown)
											wait(0.2)
											animTrack:Stop(typ[v.Key][2])
											print(v.Key.." played for "..v.HeldDown.." seconds.")
										end)()
									else
										script.Played.AnimationId = typ[v.Key][1]
										pauseableWait(v.Time-keys[i-1].Time)
										coroutine.wrap(function()
											local animTrack =  bot.AnimationController.Animator:LoadAnimation(script.Played)
											animTrack.Priority = Enum.AnimationPriority.Action
											animTrack:Play(typ[v.Key][2])
											animTrack.Looped = true
											print(v.Key.." played "..(v.Time-keys[i-1].Time).." seconds after "..keys[i-1].Key.. " was played.")
											pauseableWait(v.HeldDown)
											wait(0.2)
											animTrack:Stop(typ[v.Key][2])
											print(v.Key.." played for "..v.HeldDown.." seconds.")
										end)()
									end
								end
							end
						end
					end
				end)()
				repeat
					seconds = tick()-startTime
					script.Parent.timer.Text = string.format("%d:%.02d", seconds/60, seconds%60, seconds*1000%1000)
					wait(0.001)
				until seconds >= length
				script.Parent.timer.Text = "Length: " ..string.format("%d:%.02d", length/60, length%60, length*1000%1000)
				playing = false
				print(keys)
				table.sort(keys,function(a,b)
					return a["Time"] < b["Time"]
				end)
				print(keys)
				script.Parent.startrecording.Text = "START"
				script.Parent.startrecording.Visible = false
				script.Parent.Frame.Visible = true
			else
				while playing do
					seconds = tick()-startTime
					script.Parent.timer.Text = string.format("%d:%.02d", seconds/60, seconds%60, seconds*1000%1000)
					wait(0.001)
				end
			end
		end)()
		if length == nil then
			script.Parent.startrecording.Text = "STOP"
		else
			script.Parent.startrecording.Text = "LENGTH: "..string.format("%d:%.02d", length/60, length%60, length*1000%1000)
		end
	elseif script.Parent.startrecording.Text == "STOP" then
		length = tick()-startTime
		script.Parent.timer.Text = "Length: " ..string.format("%d:%.02d", length/60, length%60, length*1000%1000)
		playing = false
		script.Parent.startrecording.Text = "START"
		script.Parent.startrecording.Visible = false
		script.Parent.Frame.Visible = true
	end
end)

Don’t know what my scripter did wrong here, since he doesnt really know how to fix this either, if anybody has a solution for this, it would be appreciated.

In case you didn’t understand how this works: a Key in my keyboard plays an animation on the rig, Press and hold, it’s like a piano but instead of sounds its just animations.

1 Like

There’s a lot wrong with this code just taking a glance at it, I would recommend redoing the system if your scripter wants to. There’s unnecessary checks and coroutines, along with the lack of functions which makes it harder to debug and understand. My recommendation is to store the tick at which the input occurs and when it ends, but converted down into local time by subtracting the start time from the recording of each input. Then for the playback you should be able to simulate the start and end of each input

1 Like

Thanks for replying, i will let my scripter know about this and once we achieve what you suggested we will mark it as the solution.