Запуск макроса для либре врайтера на ЯП Питон по клику ПКМ

Автор Ципихович Эндрю, 25 февраля 2026, 13:30

0 Пользователи и 1 гость просматривают эту тему.

Ципихович Эндрю

здравствуйте, мне нужен макрос для либре врайтера на ЯП Питон - нужно когда курсор стоит внутри формулы ЛаТекст, например $S = \pi r^2$  после клика ПКМ должен быть звук и чтобы выделилась вся формула, мой код:
from com.sun.star.awt import XWindowPeer
from com.sun.star.uno import RuntimeException
import uno
import winsound

def select_latex_formula():
    # Подключение к текущему экземпляру LibreOffice
    local_context = uno.getComponentContext()
    smgr = local_context.ServiceManager
    desktop = smgr.createInstanceWithContext('com.sun.star.frame.Desktop', local_context)
    model = desktop.getCurrentComponent()
    controller = model.getCurrentController()
    view_cursor = controller.getViewCursor()

    # Получение текущего содержимого и позиции курсора
    text_content = view_cursor.getString()
    start_position = view_cursor.getStart().getPropertyValue('Position')
    end_position = view_cursor.getEnd().getPropertyValue('Position')

    # Поиск ближайших символов $
    dollar_before = text_content.rfind('$', 0, start_position)
    dollar_after = text_content.find('$', start_position+1)

    # Проверка наличия валидной формулы вокруг курсора
    if dollar_before >= 0 and dollar_after > dollar_before:
        # Устанавливаем положение начала и конца выделения
        view_cursor.setStart(view_cursor.getStart())
        view_cursor.setEnd(view_cursor.getEnd())
        view_cursor.gotoRange(model.Text.createTextCursorByRange(
            model.Text.createTextCursorByRange(model.Text.createTextCursorByOffset(dollar_before))),
                              False)
        view_cursor.gotoRange(model.Text.createTextCursorByRange(
            model.Text.createTextCursorByOffset(dollar_after+1)),
                              True)

        # Произведём звуковой сигнал
        winsound.MessageBeep(winsound.MB_OK)

# Экспорт функции для вызова из LibreOffice
g_exportedScripts = (select_latex_formula,)
не работает, как исправить?
сразу скажу, что сие делается так как установил, что выделяя самому формулу как я установил её не заменить на картинку формулы - то есть выделение текста плохой тригер для этого, подумал, может клик ПКМ внутри формулы сработает? спасибо

Ципихович Эндрю

#1
здравствуйте, вот пример из рабочего макроса:
# Класс-обработчик события выделения текста Selection Listener=слушатель выделения
class SelectionListener(unohelper.Base, XSelectionChangeListener):
    def __init__(self):
        pass
    def selectionChanged(self, event):
        OnTextSelected(event)
    def disposing(self, event):
        pass
значит видимо нужен класс для клика ПКМ? в Ворде да - это решается наличием класса, а в либре врайтере как обстоит дело? как вариант настройка, которая делается вручную, как? но по опыту с Вордом я знаю, что множество того, что делается в настройках делается и макросом, проясните пожалуйста

Ципихович Эндрю

чуть сдвинулся - всё таки макрос нужен и сможет быть сделана реализация без ручной настройки, остановился на этом:
from com.sun.star.awt import XMouseListener
import unohelper

# Пространство имен (ctx) понадобится для всех последующих операций
ctx = uno.getComponentContext()
smgr = ctx.ServiceManager

# Функция вывода всплывающего окна
def show_message(title, message):
    try:
        # Получаем Toolkit
        toolkit = smgr.createInstanceWithContext("com.sun.star.awt.Toolkit", ctx)
       
        # Получаем активное окно
        desktop = smgr.createInstanceWithContext("com.sun.star.frame.Desktop", ctx)
        frame = desktop.getCurrentFrame()
        parent_window = frame.getContainerWindow()
       
        # Создаем и показываем Message Box
        box = toolkit.createMessageBox(parent_window, "infobox", 1, title, message)
        box.execute()
        box.dispose()
    except Exception as e:
        print(f"Ошибка: {e}")  # Сообщения записываются в журнал макросов

# Класс-обработчик событий мыши
class MouseClickHandler(unohelper.Base, XMouseListener):
    def __init__(self, ctx):
        self.ctx = ctx
        show_message("Инициализация", "Инициализирован обработчик событий мыши")

    # Метод вызывается при нажатии кнопки мыши
    def mousePressed(self, ev):
        if ev.Buttons & 8 != 0:  # Проверяем, была ли нажата правая кнопка мыши
            show_message("Сообщение", "Вы кликнули правой кнопкой мыши.")

    # Оставшиеся методы оставляем пустыми, так как они нам не нужны
    def mouseReleased(self, ev): pass
    def mouseEntered(self, ev): pass
    def mouseExited(self, ev): pass
    def disposing(self, ev): pass

# Функция регистрации обработчика
def register_mouse_listener():
    global ctx
    try:
        desktop = smgr.createInstanceWithContext("com.sun.star.frame.Desktop", ctx)
        doc = desktop.getCurrentComponent()
        frame = doc.CurrentController.Frame
        window = frame.ContainerWindow
        handler = MouseClickHandler(ctx)
        window.addMouseListener(handler)
        show_message("Регистрация", "Обработчик зарегистрирован успешно")
    except Exception as e:
        show_message("Ошибка", f"Ошибка регистрации обработчика: {e}")

# Функция, запускаемая при открытии документа
def onOpenDoc(event):
    show_message("Начало", "Открыт документ")
    register_mouse_listener()

# Экспортируем функцию
g_exportedScripts = (onOpenDoc,)
что-то не работает - нет НИ единого сообщения, ЧЯДНТ? спасибо

Ципихович Эндрю

здравствуйте, подскажите в макросе
import uno
from com.sun.star.awt import XMouseListener
import unohelper

ctx = uno.getComponentContext()
smgr = ctx.ServiceManager

def Message_box(title, message):
    try:
        toolkit = smgr.createInstanceWithContext("com.sun.star.awt.Toolkit", ctx)
        desktop = smgr.createInstanceWithContext("com.sun.star.frame.Desktop", ctx)
        frame = desktop.getCurrentFrame()
        if frame:
            window = frame.getContainerWindow()
            msgbox = toolkit.createMessageBox(
                window,
                'infobox',
                1,
                title,
                message
            )
            msgbox.execute()
            msgbox.dispose()
        else:
            print(f"{title}: {message}")
    except Exception as e:
        print(f"Ошибка показа сообщения: {e}")

class MouseHandler(unohelper.Base, XMouseListener):
    def __init__(self, ctx):
        self.ctx = ctx
        self.click_count = 0

    def mousePressed(self, ev):
        self.click_count += 1
        Message_box('Событие мыши', f'Клик #{self.click_count}! Координаты: X={ev.X}, Y={ev.Y}')

    def mouseReleased(self, ev): pass
    def mouseEntered(self, ev): pass
    def mouseExited(self, ev): pass

def start_mouse_handler(_=None):
    try:
        desktop = smgr.createInstanceWithContext("com.sun.star.frame.Desktop", ctx)
        doc = desktop.getCurrentComponent()
        if not doc:
            Message_box('Ошибка', 'Документ не найден')
            return

        controller = doc.CurrentController
        if not controller:
            Message_box('Ошибка', 'Контроллер документа не найден')
            return

        frame = controller.getFrame()
        if not frame:
            Message_box('Ошибка', 'Фрейм документа не найден')
            return

        # Получаем компонент текстового редактора
        try:
            # Основной компонент для событий мыши в Writer
            component = controller.getViewCursor().getText()
        except:
            # Запасной вариант: контейнер окна
            component = frame.getContainerWindow()

        handler = MouseHandler(ctx)

        # Регистрируем обработчик
        try:
            component.addMouseListener(handler)
            Message_box('Результат', 'Обработчик зарегистрирован успешно. Кликните в документе!')
        except Exception as e:
            Message_box('Ошибка регистрации', f'Не удалось добавить обработчик: {str(e)}')

    except Exception as e:
        Message_box('Критическая ошибка', f'{str(e)}')

g_exportedScripts = (start_mouse_handler,)
получаю сообщение: Не удалось добавить обработчик: addMouseListener
что здесь:
component.addMouseListener(handler)
не так?

mikekaganski

Цитата: Ципихович Эндрю от  4 марта 2026, 11:06что здесь:
component.addMouseListener(handler)
не так?

"Не так" не здесь, а там, где определяется component. Он у Вас почему-то может оказаться XText (когда определяется как controller.getViewCursor().getText()), а может быть и XWindow (если задаётся frame.getContainerWindow()). Ну так это два совершенно разных интерфейса; второй - это окно, и действительно может регистрировать слушателя событий мыши. А первый - вообще не имеет отношения к окну и его событиям; это объект из модели документа.
С уважением,
Михаил Каганский

Ципихович Эндрю

Цитата: mikekaganski от  4 марта 2026, 11:29это окно, и действительно может регистрировать слушателя событий мыши
ок спасибо - работаю с ним, опять затык:
import uno
from com.sun.star.awt import XMouseListener
import unohelper

ctx = uno.getComponentContext()
smgr = ctx.ServiceManager

def Message_box(title, message):
    try:
        toolkit = smgr.createInstanceWithContext("com.sun.star.awt.Toolkit", ctx)
        desktop = smgr.createInstanceWithContext("com.sun.star.frame.Desktop", ctx)
        frame = desktop.getCurrentFrame()
        if frame:
            window = frame.getContainerWindow()
            msgbox = toolkit.createMessageBox(
                window,
                'infobox',
                1,
                title,
                message
            )
            msgbox.execute()
            msgbox.dispose()
        else:
            print(f"{title}: {message}")
    except Exception as e:
        print(f"Ошибка показа сообщения: {e}")

class MouseHandler(unohelper.Base, XMouseListener):
    def __init__(self, ctx):
        self.ctx = ctx
        self.click_count = 0

    def mousePressed(self, ev):
        button = ev.Buttons
        if button & 1 != 0:  # Левая кнопка мыши
            self.click_count += 1
            Message_box('Событие мыши', f'Левый клик №{self.click_count}. Координаты: X={ev.X}, Y={ev.Y}')
        elif button & 2 != 0:  # Правая кнопка мыши
            self.click_count += 1
            Message_box('Событие мыши', f'Правый клик №{self.click_count}. Координаты: X={ev.X}, Y={ev.Y}')
   
    def mouseReleased(self, ev): pass
    def mouseEntered(self, ev): pass
    def mouseExited(self, ev): pass

def start_mouse_handler(_=None):
    try:
        desktop = smgr.createInstanceWithContext("com.sun.star.frame.Desktop", ctx)
        doc = desktop.getCurrentComponent()
        if not doc:
            Message_box('Ошибка', 'Документ не найден')
            return

        controller = doc.CurrentController
        if not controller:
            Message_box('Ошибка', 'Контроллер документа не найден')
            return

        frame = controller.getFrame()
        if not frame:
            Message_box('Ошибка', 'Фрейм документа не найден')
            return

        # Корневое окно документа
        root_window = frame.getContainerWindow()
        if hasattr(root_window, "addMouseListener"):
            handler = MouseHandler(ctx)
            root_window.addMouseListener(handler)
            Message_box('Результат', 'Обработчик зарегистрированных событий мыши успешно настроен.')
        else:
            Message_box('Ошибка', 'Корневое окно не поддерживает события мыши.')

    except Exception as e:
        Message_box('Критическая ошибка', str(e))

g_exportedScripts = (start_mouse_handler,)
сообщений при клике мыши нет, а принудительно выполнив макрос получаю месседж
Обработчик зарегистрированных событий мыши успешно настроен.
в чём моя ошибка?

sokol92

Вы выбираете самые сложные пути.

1. Для прослушивания событий нажатия клавиш мыши в текстовом документе LibreOffice есть специализированный интерфейс контроллера документа XMouseClickHandler.
Обратите внимание, что функции обработки событий mousePressed и mouseReleased должны вернуть логическое значение (False, True).

2. Правая кнопка мыши для выделения чего бы то ни было - неудачная идея.
Вы должны в этом случае обработать именно событие mousePressed и вернуть False (не "мое" нажатие кнопки) или True (я обработал это событие). Проблема в том, что в этом момент объект, по которому Вы щелкнули, еще не выделен и Вам придется по координатам X, Y определять, куда же Вы щелкнули.
Если обрабатывать, к примеру, щелчок левой кнопки мыши, то можно обрабатывать событие mouseReleased и объект при этом будет выделен.

Вот измененный Ваш макрос, который выдает информацию о событии mouseReleased (тщательно не тестировал):

import uno
from com.sun.star.awt import XMouseClickHandler
import unohelper

ctx = uno.getComponentContext()
smgr = ctx.ServiceManager
handler = None

def Message_box(title, message):
    try:
        toolkit = smgr.createInstanceWithContext("com.sun.star.awt.Toolkit", ctx)
        desktop = smgr.createInstanceWithContext("com.sun.star.frame.Desktop", ctx)
        frame = desktop.getCurrentFrame()
        if frame:
            window = frame.getContainerWindow()
            msgbox = toolkit.createMessageBox(
                window,
                'infobox',
                1,
                title,
                message
            )
            msgbox.execute()
            msgbox.dispose()
        else:
            print(f"{title}: {message}")
    except Exception as e:
        print(f"Ошибка показа сообщения: {e}")

class MouseHandler(unohelper.Base, XMouseClickHandler):
    def __init__(self):
        self.click_count = 0

    def mousePressed(self, ev):
        return False
  
    def mouseReleased(self, ev):
        Message_box('Событие mouseReleased', str(ev))
        return False      
      
    def disposing(self, ev):
        pass
       

def start_mouse_handler(_=None):
    global handler
    try:
        desktop = smgr.createInstanceWithContext("com.sun.star.frame.Desktop", ctx)
        doc = desktop.getCurrentComponent()
        if not doc:
            Message_box('Ошибка', 'Документ не найден')
            return
        controller = doc.CurrentController
        if handler == None:
            handler = MouseHandler()
        controller.addMouseClickHandler(handler)

    except Exception as e:
        Message_box('Критическая ошибка', str(e))

g_exportedScripts = (start_mouse_handler,)
Владимир.

Ципихович Эндрю

Цитата: sokol92 от  4 марта 2026, 18:02Вот измененный Ваш макрос, который выдает информацию о событии mouseReleased (тщательно не тестировал)
опробовал-ничего не происходит во врайтере...
Цитата: sokol92 от  4 марта 2026, 18:02Правая кнопка мыши для выделения чего бы то ни было - неудачная идея
так это задумано очень давно - юзеры привыкли делать или
1 клик ПКМ - сразу без разговоров появляется меню - в него я планирую добавлять нужный пункт - в самом низу меню
2 двойной клик ЛКМ - тогда слово выделяется - тоже как вариант подойдёт - как говорится пусть будет в арсенале, но в моём случае, если кликать внутри формулы $S = \pi r^2$ - так как это НЕ слово и будет выделен только один из её элементов

economist

Листнеры добавят неприятное дрожание, неожиданные скроллы экрана итп артефакты, всё будет плавно нарастать по мере наворачивания доп. функций. В итоге станет неприятно пользоваться "заряженным" Writer.

Еще не поздно остановиться и добиться результата в чем-то простом - готовом расширении, или макросом по хоткею на выделенном заранее фрагменте текста.
Пить не буду коньяка - читану Питоньяка!

Ципихович Эндрю

Цитата: economist от  5 марта 2026, 11:21Листнеры добавят неприятное дрожание, неожиданные скроллы экрана итп артефакты, всё будет плавно нарастать по мере наворачивания доп. функций. В итоге станет неприятно пользоваться "заряженным" Writer.
приехали.........
Цитата: economist от  5 марта 2026, 11:21Еще не поздно остановиться и добиться результата в чем-то простом
Цитата: economist от  5 марта 2026, 11:21на выделенном заранее фрагменте текста
так по этому вопросу тоже приехали в моём топике - чуть раньше
Цитата: Ципихович Эндрю от 23 февраля 2026, 08:54
ЦитироватьУ меня тоже не получается стабилизировать поведение макроса.
это сообщения с другого топика, где говорится, что после выделения текста, чтобы вставило на место выделения картинку
в таких случаях говорили ранее - до изобретения тосола - сливай воду))

economist

Выделить слово целиком и запустить любой макрос/ЯП или команду можно за два шажка:
- Ctrl+влево, Ctrl+Shift+вправо или даблклик мышью по слову
- хоткей на макрос/команду (Сервис-Настройка...)
Пить не буду коньяка - читану Питоньяка!

Ципихович Эндрю

Цитата: economist от  5 марта 2026, 14:29Выделить слово целиком и запустить любой макрос/ЯП или команду
поднимите мне веки))-выделил слово-всё это триггер для запуска макроса - НО Либра не справляется (если есть мнение, что будут лишние срабатывания - так нет, для этого можно поставить 3-4 условия и будет всё верно)
Цитата: economist от  5 марта 2026, 14:29хоткей на макрос/команду (Сервис-Настройка...)
Хоткей на макрос — это комбинация клавиш (или отдельная клавиша), назначенная для запуска заранее записанной последовательности действий (макроса)-считаю, что юзерам будет лень запоминать эти комбинации
Цитата: economist от  5 марта 2026, 14:29даблклик мышью по слову
НЕ подходит я говорил:
Цитата: Ципихович Эндрю от  5 марта 2026, 09:17если кликать внутри формулы $S = \pi r^2$ - так как это НЕ слово и будет выделен только один из её элементов
Цитата: economist от  5 марта 2026, 11:21Листнеры добавят неприятное дрожание, неожиданные скроллы экрана итп артефакты, всё будет плавно нарастать по мере наворачивания доп. функций. В итоге станет неприятно пользоваться "заряженным" Writer
economist
1 Вы наверное в курсе, что Ворд в этом вопросе выигрывает?
2 а почему бы Вам не обратиться с этим вопросом в bugs.documentfoundation.org? - Вы наверное и английский язык знаете... я то и по-русски не очень, а по-английски с переводчиком-это будет та ещё дремучая смесь))
PS
я же правильно понял, что без разницы будет это макрос на питоне, бейсике или оставшихся игроках автоматизации Либры?

bigor

Цитата: Ципихович Эндрю от  5 марта 2026, 09:17ничего не происходит во врайтере...
клик ЛКМ выводит довольно объемное сообщение
Поддержать наш форум можно здесь

economist

О чем я в курсе и опробовал лично - написал. Word это ужасный текстовый процессор, который удивляет каждый божий день. То как он работает с таблицами и "держит вёрстку", как говорим мы, издатели, не позволяет его вообще всерьез воспринимать как ПО. И какой конфеткой на этом фоне стал за эти годы LO Writer - это пример синергии OSS и неравнодушных профи из этой среды.

Ваша задача уже имеет решения, а мне интересны задачи нерешённые и особенно нерешаемые. Баги/фичреквы не пишу, но горячо поддерживаю тех кто не ленится.

Однако средства на цель не должны кратно превышать полезный эффект или просто время на ручное выполнение. Вот вы кмк давно превысили. В неверном направлении можно идти долго, а мудрость иногда состоит в том чтобы вернуться по своим следам назад и начать заново.
Пить не буду коньяка - читану Питоньяка!

Ципихович Эндрю

Цитата: bigor от  5 марта 2026, 21:29клик ЛКМ выводит довольно объемное сообщение
клик левой клавишей мыши во врайтере - что-то выдаёт? вау, у меня нет)) можно подробностей? спасибо