|
| 1 | +-- ROBLOX upstream: no upstream |
| 2 | +local Packages = script.Parent.Parent |
| 3 | + |
| 4 | +local LuauPolyfill = require(Packages.LuauPolyfill) |
| 5 | +local Error = LuauPolyfill.Error |
| 6 | + |
| 7 | +local virtualInput = game:GetService("VirtualInputManager") |
| 8 | + |
| 9 | +local function getRoot(child): Instance |
| 10 | + local parent = child.Parent :: Instance |
| 11 | + if parent == nil then |
| 12 | + return child |
| 13 | + end |
| 14 | + |
| 15 | + while parent.Parent ~= nil and (parent.Parent :: Instance).Parent ~= game do |
| 16 | + parent = parent.Parent |
| 17 | + end |
| 18 | + return parent |
| 19 | +end |
| 20 | + |
| 21 | +local function makeInteractable(fn: any) |
| 22 | + return function(element, data) |
| 23 | + local coreGui_ = element:FindFirstAncestorOfClass("CoreGui") |
| 24 | + local screenGui_ = element:FindFirstAncestorOfClass("ScreenGui") |
| 25 | + local coreGui = if coreGui_ then coreGui_ else game:GetService("CoreGui") |
| 26 | + local screenGui = (if screenGui_ then screenGui_ else Instance.new("ScreenGui")) :: ScreenGui |
| 27 | + local root |
| 28 | + local cleanupCore = false |
| 29 | + |
| 30 | + if not screenGui:FindFirstAncestorOfClass("CoreGui") and screenGui.Parent == nil then |
| 31 | + screenGui.Parent = coreGui |
| 32 | + cleanupCore = true |
| 33 | + end |
| 34 | + |
| 35 | + if not element:FindFirstAncestorOfClass("ScreenGui") then |
| 36 | + root = getRoot(element) |
| 37 | + root.Parent = screenGui |
| 38 | + end |
| 39 | + |
| 40 | + fn(element, data) |
| 41 | + |
| 42 | + if screenGui_ ~= screenGui then |
| 43 | + root.Parent = nil |
| 44 | + screenGui:Destroy() |
| 45 | + end |
| 46 | + |
| 47 | + if screenGui and cleanupCore then |
| 48 | + screenGui.Parent = nil |
| 49 | + end |
| 50 | + end |
| 51 | +end |
| 52 | + |
| 53 | +local function getCenter(element: Instance): (number, number) |
| 54 | + local position = (element :: any).AbsolutePosition |
| 55 | + local size = (element :: any).AbsoluteSize |
| 56 | + |
| 57 | + return position.X + size.X / 2, position.Y + size.Y / 2 |
| 58 | +end |
| 59 | + |
| 60 | +local function click(element: Instance) |
| 61 | + local x, y = getCenter(element) |
| 62 | + local mouseButton = 0 |
| 63 | + local layerCollector = nil |
| 64 | + local repeatCount = 1 |
| 65 | + |
| 66 | + virtualInput:SendMouseButtonEvent(x, y, mouseButton, true, layerCollector, repeatCount) |
| 67 | + virtualInput:SendMouseButtonEvent(x, y, mouseButton, false, layerCollector, repeatCount) |
| 68 | + virtualInput:WaitForInputEventsProcessed() |
| 69 | +end |
| 70 | + |
| 71 | +local function keyDown(_element: Instance, data: { key: Enum.KeyCode }) |
| 72 | + if not data or not data.key then |
| 73 | + error("No key set for event") |
| 74 | + end |
| 75 | + virtualInput:SendKeyEvent(true, data.key, false, nil) |
| 76 | + virtualInput:WaitForInputEventsProcessed() |
| 77 | +end |
| 78 | + |
| 79 | +local function keyUp(_element: Instance, data: { key: Enum.KeyCode }) |
| 80 | + if not data or not data.key then |
| 81 | + error("No key set for event") |
| 82 | + end |
| 83 | + virtualInput:SendKeyEvent(false, data.key, false, nil) |
| 84 | + virtualInput:WaitForInputEventsProcessed() |
| 85 | +end |
| 86 | + |
| 87 | +local function change(element: Instance, data: { target: { [string]: any } }) |
| 88 | + if element:IsA("TextBox") then |
| 89 | + if data and data.target then |
| 90 | + for k, v in pairs(data.target) do |
| 91 | + (element :: any)[k] = v |
| 92 | + end |
| 93 | + end |
| 94 | + else |
| 95 | + error(Error.new("The change event must be fired in a TextBox Instance")) |
| 96 | + end |
| 97 | +end |
| 98 | + |
| 99 | +local function resize(element: TextBox, data: { value: string }) |
| 100 | + local value = if data and data.value then data.value else (element :: any).Size |
| 101 | + element.Size = value |
| 102 | +end |
| 103 | + |
| 104 | +local events = { |
| 105 | + click = makeInteractable(click), |
| 106 | + keyDown = makeInteractable(keyDown), |
| 107 | + keyUp = makeInteractable(keyUp), |
| 108 | + change = makeInteractable(change), |
| 109 | + resize = makeInteractable(resize), |
| 110 | +} |
| 111 | + |
| 112 | +local function dispatchEvent(element: Instance, eventName: string, data: { [string]: any }?) |
| 113 | + local eventFn = events[eventName] |
| 114 | + if not eventFn then |
| 115 | + error("Event not found") |
| 116 | + end |
| 117 | + eventFn(element, data) |
| 118 | +end |
| 119 | + |
| 120 | +return dispatchEvent |
0 commit comments