Hello. To get to the point, I am working on a Studio Chat plugin.
Basically, whenever I press Shift + Return / Enter, I want a TextBox to create a new line.
I will not be using the Multiline property for TextBoxes since you do not need to hold Shift to create a new line.
Here are the codes I tried:
#1:UserInputService:IsKeyDown()
-- RunContext Plugin
local TextBox: TextBox = widget.TextBox
local UserInputService = game:GetService("UserInputService")
TextBox.FocusLost:Connect(function(enterPressed)
if not enterPressed then return end
if UserInputService:IsKeyDown(Enum.KeyCode.LeftShift) or UserInputService:IsKeyDown(Enum.KeyCode.RightShift) then
TextBox:CaptureFocus()
print("New line")
-- rest of the code....
end
end
It seems that neither of them were being detected.
#2:holdsShift variable via InputBegan & InputEnded
-- RunContext Plugin
local TextBox: TextBox = widget.TextBox
local UserInputService = game:GetService("UserInputService")
local holdsShift = false
UserInputService.InputBegan:Connect(function(input)
if input.KeyCode == Enum.KeyCode.LeftShift or input.KeyCode == Enum.KeyCode.RightShift then
print("InputBegan Shift")
holdsShift = true
end
end
UserInputService.InputEnded:Connect(function(input)
if input.KeyCode == Enum.KeyCode.LeftShift or input.KeyCode == Enum.KeyCode.RightShift then
print("InputEnded Shift")
holdsShift = false
end
end
TextBox.FocusLost:Connect(function(enterPressed)
if not enterPressed then return end
if holdsShift then
TextBox:CaptureFocus()
print("New line")
-- rest of the code....
end
end
This did detect Shift, however, it seems that as soon as you focus on the TextBox it sets the variable to false.
Is there anything I can do to fix this? Are there any workarounds or a plugin function for detecting keybinds? Please let me know.
i got the same question as you like 2 weeks ago! anyways here’s what I got:
local TextBox = widget.TextBox
local UserInputService = game:GetService("UserInputService")
local handledEnter = false
local function getCursorIndex()
local text = TextBox.Text or ""
local index = TextBox.SelectionStart
if not index or index < 0 then
index = TextBox.CursorPosition or 0
end
if index < 0 then index = 0 end
local len = #text
if index > len then index = len end
return index
end
local function insertAtCursor(insertStr)
local text = TextBox.Text or ""
local index = getCursorIndex()
local left = text:sub(1, index)
local right = text:sub(index + 1)
local newText = left .. insertStr .. right
TextBox.Text = newText
local success = pcall(function()
TextBox.CursorPosition = index + #insertStr
end)
TextBox:CaptureFocus()
return success
end
UserInputService.InputBegan:Connect(function(input, gpi)
if gpi then return end
if input.UserInputType == Enum.UserInputType.Keyboard then
local key = input.KeyCode
if (key == Enum.KeyCode.Return or key == Enum.KeyCode.KeypadEnter) and TextBox:IsFocused() then
if UserInputService:IsKeyDown(Enum.KeyCode.LeftShift) or UserInputService:IsKeyDown(Enum.KeyCode.RightShift) then
handledEnter = true
insertAtCursor("\n")
end
end
end
end)
TextBox.FocusLost:Connect(function(enterPressed)
if handledEnter then
handledEnter = false
return
end
if not enterPressed then
return
end
end)
TextBox.Focused:Connect(function() end)
Using your code, it turns out nothing past the key variable part works. Here is everything I’ve changed in your code:
UserInputService.InputBegan:Connect(function(input, gpi)
if not gpi then return end -- Reversed gpi so it detects when you're pressing keys even if you are focused
if input.UserInputType == Enum.UserInputType.Keyboard then
local key = input.KeyCode
print(key)
-- Nothing happens past this point
if (key == Enum.KeyCode.Return or key == Enum.KeyCode.KeypadEnter) and TextBox:IsFocused() then
print("Is focused")
if UserInputService:IsKeyDown(Enum.KeyCode.LeftShift) or UserInputService:IsKeyDown(Enum.KeyCode.RightShift) then
handledEnter = true
print("New line")
insertAtCursor("\n")
end
end
end
end)
TextBox.FocusLost:Connect(function(enterPressed)
if handledEnter then
handledEnter = false
print("Handled enter") -- Doesn't print
return
end
print("No new line")
if not enterPressed then
return
end
end)
Well my script actually works on my end so maybe its the way you used it? anyways your script have mistakes, sorry!
that basically stopped everything from running. youre basically saying “if roblox did NOT process the input, stop running.” so yea never write this line in any code ever
also i changed my code a bit check it out!
local TextBox = widget.TextBox
local UserInputService = game:GetService("UserInputService")
local handledEnter = false
local function getCursorIndex()
local text = TextBox.Text
local index = TextBox.CursorPosition
if index == -1 then
index = #text + 1
end
index = math.clamp(index, 1, #text + 1)
return index
end
local function insertAtCursor(insertStr)
local text = TextBox.Text
local index = getCursorIndex()
local left = text:sub(1, index - 1)
local right = text:sub(index)
local newText = left .. insertStr .. right
TextBox.Text = newText
task.defer(function() --no throttle
TextBox.CursorPosition = index + #insertStr
end)
return true
end
UserInputService.InputBegan:Connect(function(input, gpi)
if gpi then return end
if input.UserInputType == Enum.UserInputType.Keyboard then
local key = input.KeyCode
if (key == Enum.KeyCode.Return or key == Enum.KeyCode.KeypadEnter) and TextBox:IsFocused() then
if UserInputService:IsKeyDown(Enum.KeyCode.LeftShift) or UserInputService:IsKeyDown(Enum.KeyCode.RightShift) then
handledEnter = true
insertAtCursor("\n")
end
end
end
end)
TextBox.FocusLost:Connect(function(enterPressed)
if handledEnter then
handledEnter = false
return
end
if not enterPressed then
return
end
end)
TextBox.Focused:Connect(function() end)
I really don’t know what I could be doing wrong here.
As I was saying, I tested this in a newly created place and I pasted your exact code:
local TextBox = script.Parent
local UserInputService = game:GetService("UserInputService")
local handledEnter = false
local function getCursorIndex()
local text = TextBox.Text
local index = TextBox.CursorPosition
if index == -1 then
index = #text + 1
end
index = math.clamp(index, 1, #text + 1)
return index
end
local function insertAtCursor(insertStr)
local text = TextBox.Text
local index = getCursorIndex()
local left = text:sub(1, index - 1)
local right = text:sub(index)
local newText = left .. insertStr .. right
TextBox.Text = newText
task.defer(function() --no throttle
TextBox.CursorPosition = index + #insertStr
end)
return true
end
UserInputService.InputBegan:Connect(function(input, gpi)
if gpi then return end
if input.UserInputType == Enum.UserInputType.Keyboard then
local key = input.KeyCode
if (key == Enum.KeyCode.Return or key == Enum.KeyCode.KeypadEnter) and TextBox:IsFocused() then
if UserInputService:IsKeyDown(Enum.KeyCode.LeftShift) or UserInputService:IsKeyDown(Enum.KeyCode.RightShift) then
handledEnter = true
insertAtCursor("\n")
end
end
end
end)
TextBox.FocusLost:Connect(function(enterPressed)
if handledEnter then
handledEnter = false
return
end
if not enterPressed then
return
end
end)
TextBox.Focused:Connect(function() end)
Yet when I press Shift + Enter, it just seems to lose focus.
Since it is a new place, the Script’s run context is Client.
Instead of checking Shift during FocusLost, detect Enter in InputBegan while the textbox is focused.
This lets you check Shift and Enter at the same time, before the textbox loses focus.
InputBegan runs before the textbox processes Enter and you’d use IsKeDown() to correctly report Shift.
Something like:
if gameProcessed then return end
if not TextBox:IsFocused() then return end
if input.KeyCode == Enum.KeyCode.Return then
if UserInputService:IsKeyDown(Enum.KeyCode.LeftShift)
or UserInputService:IsKeyDown(Enum.KeyCode.RightShift) then
TextBox.Text ..= "\n"
print("New line")
end
end
I already implemented @qushenya’s code and turns out if you enable multiline it works. There is one issue where pressing Enter (without holding Shift) adds a new line too, but you can just remove that using TextBox.Text:sub(1, -2).
I am not quite sure what to mark as the solution here.
local TextBox = widget.TextBox
local UserInputService = game:GetService("UserInputService")
local handledEnter = false
TextBox.MultiLine = true
TextBox.ClearTextOnFocus = false
local function getCursorIndex()
local text = TextBox.Text
local index = TextBox.CursorPosition
if index == -1 then
index = #text + 1
end
index = math.clamp(index, 1, #text + 1)
return index
end
local function insertAtCursor(insertStr)
local text = TextBox.Text
local index = getCursorIndex()
local left = text:sub(1, index - 1)
local right = text:sub(index)
local newText = left .. insertStr .. right
TextBox.Text = newText
task.defer(function()
TextBox.CursorPosition = index + #insertStr
end)
return true
end
UserInputService.InputBegan:Connect(function(input, gpi)
if gpi then return end
if input.UserInputType == Enum.UserInputType.Keyboard then
local key = input.KeyCode
if (key == Enum.KeyCode.Return or key == Enum.KeyCode.KeypadEnter) and TextBox:IsFocused() then
if UserInputService:IsKeyDown(Enum.KeyCode.LeftShift) or UserInputService:IsKeyDown(Enum.KeyCode.RightShift) then
handledEnter = true
insertAtCursor("\n")
else
TextBox:ReleaseFocus(true)
end
end
end
end)
TextBox.FocusLost:Connect(function(enterPressed)
if handledEnter then
handledEnter = false
TextBox:CaptureFocus()
return
end
if not enterPressed then
return
end
end)
TextBox.Focused:Connect(function() end)
field.MultiLine = true
field.ClearTextOnFocus = false
local internal = false
field:GetPropertyChangedSignal("Text"):Connect(function()
if internal then
internal = false
return
end
local text = field.Text
if text:sub(-2) == "\\n" then
internal = true
field.Text = text:sub(1, -3) .. "\n"
field.CursorPosition = #field.Text + 1
return
end
if text:sub(-1) == "\n" then
field.Text = text:sub(1, -2)
send()
end
end)