Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 7 additions & 3 deletions client/commands.lua
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ lib.addKeybind({
name = 'dolu_tool:open',
description = locale('command_openui', '~b~>~w~'),
defaultKey = Config.openMenuKey,
onPressed = function(self)
onPressed = function()
if Client.inputFocused then return end
if Config.usePermission and not lib.callback.await('dolu_tool:isAllowed', 100, true) then return end

if not IsNuiFocused() and not IsPauseMenuActive() then
Expand All @@ -18,7 +19,8 @@ lib.addKeybind({
name = 'tpm',
description = locale('command_tpm', '~b~>~w~'),
defaultKey = Config.teleportMarkerKey,
onPressed = function(self)
onPressed = function()
if Client.inputFocused then return end
if Config.usePermission and not lib.callback.await('dolu_tool:isAllowed', 100, true) then return end

local marker = GetFirstBlipInfoId(8)
Expand Down Expand Up @@ -84,7 +86,8 @@ lib.addKeybind({
name = 'noclip',
description = locale('command_noclip', '~b~>~w~'),
defaultKey = Config.toggleNoclipKey,
onPressed = function(self)
onPressed = function()
if Client.inputFocused then return end
if Config.usePermission and not lib.callback.await('dolu_tool:isAllowed', 100, true) then return end

Client.noClip = not Client.noClip
Expand All @@ -93,6 +96,7 @@ lib.addKeybind({
})

RegisterCommand('goback', function()
if Client.inputFocused then return end
if Config.usePermission and not lib.callback.await('dolu_tool:isAllowed', 100, true) then return end

if not Client.lastCoords then
Expand Down
9 changes: 9 additions & 0 deletions client/nui.lua
Original file line number Diff line number Diff line change
Expand Up @@ -95,10 +95,19 @@ RegisterNUICallback('dolu_tool:deleteVehicle', function(_, cb)
end
end)

RegisterNUICallback('dolu_tool:setInputFocus', function(keepGameInput, cb)
cb(1)
Client.inputFocused = not keepGameInput -- true when typing in input
if Client.isMenuOpen then
SetNuiFocusKeepInput(keepGameInput)
end
end)

RegisterNUICallback('dolu_tool:exit', function(_, cb)
cb(1)
SetNuiFocus(false, false)
SetNuiFocusKeepInput(false)
Client.inputFocused = false

SendNUIMessage({
action = 'setGizmoEntity',
Expand Down
1 change: 1 addition & 0 deletions shared/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ elseif lib.context == 'client' then
Client = {
noClip = false,
isMenuOpen = false,
inputFocused = false,
currentTab = 'home',
lastLocation = json.decode(GetResourceKvpString('dolu_tool:lastLocation')),
portalPoly = false,
Expand Down
35 changes: 21 additions & 14 deletions web/src/layouts/gizmo/TransformComponent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -49,20 +49,27 @@ export const TransformComponent = React.memo(({ space, mode, currentEntity, setC
}, []);

const handleObjectDataUpdate = useCallback((): void => {
// Just send position/rotation, let Lua decide what to do
fetchNui('dolu_tool:updateGizmoTransform', {
position: {
x: mesh.current.position.x,
y: -mesh.current.position.z,
z: mesh.current.position.y
},
rotation: {
x: MathUtils.radToDeg(mesh.current.rotation.x),
y: MathUtils.radToDeg(-mesh.current.rotation.z),
z: MathUtils.radToDeg(mesh.current.rotation.y)
}
});
}, [mesh]);
const position = {
x: mesh.current.position.x,
y: -mesh.current.position.z,
z: mesh.current.position.y
};
const rotation = {
x: MathUtils.radToDeg(mesh.current.rotation.x),
y: MathUtils.radToDeg(-mesh.current.rotation.z),
z: MathUtils.radToDeg(mesh.current.rotation.y)
};

fetchNui('dolu_tool:updateGizmoTransform', { position, rotation });

if (currentEntity) {
setCurrentEntity({
...currentEntity,
position: position as TransformEntity['position'],
rotation: rotation as TransformEntity['rotation']
});
}
}, [mesh, currentEntity, setCurrentEntity]);

const handleMouseDown = useCallback(() => {
onMouseDown?.()
Expand Down
34 changes: 34 additions & 0 deletions web/src/main.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,40 @@ import { ModalsProvider } from '@mantine/modals'
import { RecoilRoot } from 'recoil'
import LocaleProvider from './providers/LocaleProvider'
import { isEnvBrowser } from './utils/misc'
import { fetchNui } from './utils/fetchNui'

/**
* Prevents keybinds from firing while typing in input fields.
* MutationObserver catches dynamically added inputs (modals, etc.)
* and attaches focus/blur listeners that toggle SetNuiFocusKeepInput.
*/
; (() => {
const INPUT_SELECTOR = 'input, textarea, select, [contenteditable="true"], [role="combobox"], [role="textbox"], [role="spinbutton"]'
const handled = new WeakSet<Element>()

const attachListeners = (elements: NodeListOf<Element> | Element[]) => {
elements.forEach((el) => {
if (handled.has(el)) return
handled.add(el)
el.addEventListener('focus', () => fetchNui('dolu_tool:setInputFocus', false))
el.addEventListener('blur', () => fetchNui('dolu_tool:setInputFocus', true))
})
}

const processNode = (node: Node) => {
if (!(node instanceof Element)) return
if ((node as HTMLElement).matches?.(INPUT_SELECTOR)) attachListeners([node])
if (node.childNodes.length > 0) attachListeners(node.querySelectorAll(INPUT_SELECTOR))
}

new MutationObserver((mutations) => {
for (const mutation of mutations) {
for (const node of mutation.addedNodes) processNode(node)
}
}).observe(document.body, { childList: true, subtree: true })

attachListeners(document.body.querySelectorAll(INPUT_SELECTOR))
})()

if (isEnvBrowser()) {
const root = document.getElementById('root')
Expand Down