-- Переменные для отслеживания времени удержания кнопок
local holdStartTime = nil  -- Время начала удержания
local holdDelay = 300      -- Задержка перед первой активацией (мс)
local holdInterval = 100   -- Интервал повторения действия (мс)

function updateKeyHold()
    local currentTime = getGameTimer()
    local isKeyDown = isKeyDown(38)

    if isKeyDown then
        if not wasKeyDown then
            holdStartTime = currentTime
            performAction()
        elseif currentTime - holdStartTime >= holdDelay then
            performAction()
            holdStartTime = currentTime - (holdDelay - holdInterval)
        end
    else
        holdStartTime = nil
    end

    wasKeyDown = isKeyDown
end


внедри этот паттерн

в этот код

function displayMenu(menu)
	if not isMenuActive then return end

    -- Inicializacia lokal?nyh peremennyh
    local cursorX, cursorY		= getCursorPos()		-- Tekusaa pozicia kursora
    local isLMBDown				= isKeyDown(1)  		-- ?LKM? nazata
    local isRMBDown				= isKeyDown(2)  		-- ?PKM? nazata
    local currentDescription	= ""  					-- Tekusee opisanie
    local isArrowKeyDown		= false  				-- Flag nazatia strelki
	local isAnyItemHovered		= false
    local mouseWheelDelta		= getMousewheelDelta()  -- Prokrutka kolesa mysi
    local isUArrowDown			= isKeyDown(38)  		-- Vverh strelka nazata
    local isDArrowDown			= isKeyDown(40)  		-- Vniz strelka nazata
    local isLArrowDown			= isKeyDown(37)  		-- Vlevo strelka nazata
    local isRArrowDown			= isKeyDown(39)  		-- Vpravo strelka nazata
    local isEnterDown			= isKeyDown(13)  		-- Enter nazat
	local isShiftDown			= isKeyDown(16)
	local isCtrlDown			= isKeyDown(18)			-- на самом деле альт
    local isBackspaceDown		= isKeyDown(8)			-- Backspace nazat

    -- Proverka na aktivnosti SF, Chata, Dialoga i Menu pauzy
    local isNotInRestrictedMode = not isSampfuncsConsoleActive() and not sampIsChatInputActive() and not sampIsDialogActive() and not isPauseMenuActive()

    -- ?Otrisovka? zagolovka menu
    drawText(menu.title, MENU_X, MENU_Y, MENU_TITLE_SIZE, MENU_COLOR, false)

    -- Perebor elementov menu
    for i, item in ipairs(menu.items) do
        local itemY = MENU_Y + 10 + (MENU_ITEM_HEIGHT + MENU_ITEM_SPACING) * i

        if isNotInRestrictedMode then
            local isHovered = isPointInArea(cursorX, cursorY, MENU_X, itemY, MENU_ITEM_WIDTH, MENU_ITEM_HEIGHT)
            if isHovered then isAnyItemHovered = true end
			
            -- Obnovlenie fokusa na osnove navedenia mysi, esli strelki ne byli nazaty
            if isHovered and not isArrowKeyDown then
                focusIndex = i
            end
        end

        -- Opredelenie, sfokusirovan li element ili na nego naveden kursor
        local isFocused = (i == focusIndex)
        drawText(item.label, MENU_X, itemY, 1, TEXT_COLOR, isFocused or (isNotInRestrictedMode and isPointInArea(cursorX, cursorY, MENU_X, itemY, MENU_ITEM_WIDTH, MENU_ITEM_HEIGHT)))

        -- Vypolnenie dejstvij v zavisimosti ot sostoania fokusa
        if isFocused then
            currentDescription = item.description

            -- Obrabotka prokrutki kolesom mysi ili strelkami
            if isNotInRestrictedMode and mouseWheelDelta ~= 0 and item.scrollAction and isAnyItemHovered then
                item.scrollAction(mouseWheelDelta, isShiftDown, isCtrlDown)
            elseif isNotInRestrictedMode and isLArrowDown and not wasLArrowDown and item.scrollAction then
                item.scrollAction(-1, isShiftDown, isCtrlDown)
            elseif isNotInRestrictedMode and isRArrowDown and not wasRArrowDown and item.scrollAction then
                item.scrollAction(1, isShiftDown, isCtrlDown)
            end

            -- Obrabotka nazatia ?LKM? ili Enter
			if isNotInRestrictedMode and (
				(isLMBDown and not wasLMBDown and isAnyItemHovered) or
				(isEnterDown and not wasEnterDown)
			) then
				item.action()
			end
        end
    end
	

	-- Proverka vvoda so strelok i obnovlenie focusIndex s cikliceskoj navigaciej
	if isNotInRestrictedMode and not isAnyItemHovered and isUArrowDown and not wasUArrowDown then
		-- Loop to find the previous non-empty item
		repeat
			if focusIndex == 1 then
				focusIndex = #menu.items  -- Go to the last element
			else
				focusIndex = focusIndex - 1
			end
		until menu.items[focusIndex].label ~= ""
		isArrowKeyDown = true
	elseif isNotInRestrictedMode and not isAnyItemHovered and isDArrowDown and not wasDArrowDown then
		-- Loop to find the next non-empty item
		repeat
			if focusIndex == #menu.items then
				focusIndex = 1  -- Go to the first element
			else
				focusIndex = focusIndex + 1
			end
		until menu.items[focusIndex].label ~= ""
		isArrowKeyDown = true
	end
	
    -- Otobrazenie tekusego opisania pod poslednim elementom menu
    local descriptionY = MENU_Y + 15 + (MENU_ITEM_HEIGHT + MENU_ITEM_SPACING) * (#menu.items + 1)
    drawText(currentDescription, MENU_X, descriptionY, DESCRIPTION_FONT_SIZE, DESCRIPTION_COLOR, false)

    -- Pereklucenie na roditel?skoe menu, esli nazata ?PKM ili Backspace
    if isNotInRestrictedMode and ((isRMBDown and not wasRMBDown and isAnyItemHovered) or (isBackspaceDown and not wasBackspaceDown)) then
		if menu.parent then
			currentMenu = menu.parent
		else
			isMenuActive = false
			showCursor(false, false)
		end
		addOneOffSound(0, 0, 0, SOUND_BACK)
        --printStringNow("Switching to parent menu", 500)
		if not isAnyItemHovered then	-- obnulenie fokusa na pervyj ?item
			focusIndex = 1				-- esli ni odin iz ?ajtemov? ne ?hovered?
		end
    end

    -- Obnovlenie peremennyh sostoania klavis
    wasUArrowDown 		= isUArrowDown
    wasDArrowDown 		= isDArrowDown
    wasLArrowDown	 	= isLArrowDown
    wasRArrowDown 		= isRArrowDown
    wasLMBDown			= isLMBDown
    wasRMBDown			= isRMBDown
    wasEnterDown		= isEnterDown
    wasBackspaceDown	= isBackspaceDown
end

для всех нажатий стрелками ( скролл значений айтема, скролл самих айтемов )