Использование диктовки Mac внутри Python

Есть ли у кого-нибудь идеи о том, как использовать встроенный в Mac инструмент диктовки для создания строк, которые будут использоваться Python?

Чтобы запустить диктовку, нужно дважды нажать клавишу Fn в любом текстовом редакторе. Если это так, есть ли способ объединить команду нажатия клавиши с командой ввода? Что-то вроде:

Шаг 1. Смоделируйте нажатие клавиши для двойного нажатия клавиши Fn, запуска инструмента «Диктовка», а затем Шаг 2. Создание переменной с использованием содержимого преобразования речи в текст как части функции ввода, т. е. text_string = input («Начать диктант: «)

В этой теме (Могу ли я использовать распознавание/диктовку речи OS X 10.8 без графического интерфейса?) пользователь предполагает, что он понял это с помощью CGEventCreateKeyboardEvent(src, 0x3F, true), но кода нет.

Любые идеи? Примеры кода приветствуются.

ОБНОВЛЕНИЕ: Благодаря приведенным ниже предложениям я импортировал AppScript. Я пытаюсь, чтобы код работал в этом направлении, но безуспешно:

from appscript import app, its
se = app('System Events')
proc = app.processes[its.frontmost == True]
mi = proc.menu_bars[1].menu_bar_items['Edit'].menus[1].menu_items['Start Dictation']
user_voice_text = input(mi.click())
print(user_voice_text)

Любые идеи о том, как я могу включить инструмент диктовки для ввода строки?

ОБНОВЛЕНИЕ 2:

Вот простой пример программы, которую я пытаюсь создать:

Ideally i want to launch the program, and then have it ask me: "what is 1 + 1?"
Then I want the program to turn on the dictation tool, and I want the program to record my voice, with me answering "two".
The dictation-to-text function will then pass the string value = "two" to my program, and an if statement is then used to say back "correct" or "incorrect".

Я пытаюсь передать команды программе, даже не печатая на клавиатуре.


person RollingStone1234    schedule 08.09.2014    source источник
comment
Этот вопрос может быть полезен для изучения того, как использовать CGEventCreateKeyboardEvent. Кроме того, КОЙГ!   -  person dano    schedule 08.09.2014
comment
Связанный вопрос спрашивает, как использовать API iOS из OS X, поэтому я не уверен, насколько он будет полезен. Найдите API-интерфейсы OS X (которые не будут начинаться с UI и, что более важно, будут частью библиотеки разработчика Mac, а не библиотеки разработчика iOS), а затем вы можете посмотреть, можете ли вы использовать их через, например. , PyObjC или AppleEvents.   -  person abarnert    schedule 08.09.2014
comment
Кроме того, я точно не помню, но я думаю, что Quartz.CGEventCreateKeyboardEvent может быть одной из функций, которая была нарушена PyObjC 2.5, и поскольку Apple включает 2.5.1 с их предустановленным Python 2.7 с 10.7 по 10.10, вы можете получить ошибки это не имеет смысла. Попробуйте и посмотрите; если вы это сделаете, обновитесь до PyObjC 3.0 или более поздней версии.   -  person abarnert    schedule 08.09.2014
comment
Вы не можете включить инструмент диктовки для ввода строки. Когда вы запускаете диктовку, это означает, что OS X начнет вставлять текст в текущий текстовый элемент управления (и будет продолжать делать это, пока пользователь не выключит его).   -  person abarnert    schedule 11.09.2014


Ответы (1)


Во-первых, диктовка FnFn — это функция NSText (или, может быть, NSTextView?) элемента управления Cocoa. Если у вас есть один из них, продиктованный текст вставляется в этот элемент управления. (Он также использует существующий текст этого элемента управления для контекста.) С точки зрения приложения, использующего NSTextView, если вы просто создаете стандартное меню «Правка», элемент «Начать диктовку» добавляется в конец с FnFn в качестве ярлыка и все, что продиктовано, отображается как ввод, точно так же, как ввод на клавиатуре, вставка или перетаскивание с помощью мыши или с помощью любого другого метода ввода.

Итак, если у вас нет приложения с графическим интерфейсом, включение диктовки будет бессмысленным, потому что у вас нет возможности получить ввод.

Если у вас есть приложение с графическим интерфейсом, проще всего получить пункт меню через NSMenu и щелкните элемент.

Вы почти наверняка используете какую-то библиотеку с графическим интерфейсом, например PyQt или Tkinter, у которой есть собственный способ доступа к меню вашего приложения. Но если нет, вы можете сделать это напрямую через Cocoa (используя PyObjC, который поставляется с предустановленным Python от Apple, но который вам придется pip install использовать, если вы используете сторонний Python):

import AppKit
mb = AppKit.NSApp.mainMenu()
edit = mb.itemWithTitle_('Edit').submenu()
sd = edit.indexOfItemWithTitle_('Start Dictation')
edit.performActionForItemAtIndex_(sd)

Но если вы пишете консольную программу, которая запускается в терминале (будь то Terminal.app или альтернатива, такая как iTerm), приложение, под которым вы работаете, имеет свой собственный текстовый виджет и меню «Правка», и вместо этого вы можете паразитно использовать его меню. .

Проблема в том, что у вас нет разрешения просто управлять другими приложениями, если это не разрешено пользователем. В более старых версиях OS X это было сделано путем глобального включения «вспомогательных сценариев для специальных возможностей». Начиная с версии 10.10, на вкладке «Конфиденциальность» панели «Безопасность и конфиденциальность» Системных настроек есть якорь «Специальные возможности», в котором есть список приложений, у которых есть разрешения. К счастью, если вас нет в списке, при первой попытке использовать специальные возможности появится всплывающее диалоговое окно, и если пользователь нажмет на него, он запустит Системные настройки, покажет этот якорь, добавит ваш app в список с отключенным флажком и прокрутите его, чтобы все, что нужно сделать пользователю, это установить флажок.

AppleScript для этого:

tell application "System Events"
    click (menu item "Start Dictation" of menu of menu bar item "Edit" 
        of menu bar of (first process whose frontmost is true))
end tell

«Правильный» способ сделать то же самое в Python — через ScriptingBridge, доступ к которому можно получить через PyObjC… но намного проще использовать стороннюю библиотеку appscript:

from appscript import app, its
se = app('System Events')
proc = app.processes[its.frontmost == True]
mi = proc.menu_bars[1].menu_bar_items['Edit'].menus[1].menu_items['Start Dictation']
mi.click()

Если вы действительно хотите отправить клавишу Fn дважды, API-интерфейсы для создания и отправки событий клавиатуры являются частью Quartz Events Services, которые (несмотря на то, что это API CoreFoundation C, а не API Cocoa ObjC) также обернуты PyObjC. Документацию может быть немного сложно понять, но в основном идея заключается в том, что вы создаете событие соответствующего типа, а затем либо отправляете его в определенное приложение, либо в событие, либо в место касания. Таким образом, вы можете создать и отправить общесистемное событие нажатия клавиши Fn, например:

evt = Quartz.CGEventCreateKeyboardEvent(None, 63, True)
Quartz.CGEventPost(Quartz.kCGSessionEventTap, evt)

Чтобы отправить событие нажатия клавиши, просто измените True на False.

person abarnert    schedule 08.09.2014
comment
Это очень полезно, спасибо! Но я еще не там. Этот код не работает, но вам должно быть ясно, чего я пытаюсь добиться: из appscript import app его se = app('System Events') proc = app.processes[its.frontmost == True] mi = proc.menu_bars[1].menu_bar_items['Редактировать'].menus[1].menu_items['Начать диктовку'] user_voice_text = input(mi.click()) print(user_voice_text) Как заставить этот код работать? - person RollingStone1234; 11.09.2014
comment
@RollingStone1234: Я понятия не имею, что вы пытаетесь сделать. До последних двух строк это просто мой пример кода. Затем вы вызываете input(mi.click()), который будет печатать все, что возвращается mi.click() (который, я думаю, будет либо None, либо aem объектом) в качестве подсказки, ждете, пока пользователь введет строку текста на консоли, и возвращаете этот текст. Итак… почему? Чего вы пытаетесь достичь, передавая mi.click() в input()? - person abarnert; 11.09.2014
comment
Да, я пытаюсь создать переменную с именем user_voice_text, которая определяется выводом инструмента диктовки... пример: в идеале я хочу запустить программу, а затем она спросит меня: что такое 1 + 1? Затем я хочу, чтобы программа включила инструмент диктовки, и я хочу ответить на два. Затем функция диктовки в текст передаст моей программе строковое значение = два, а затем используется оператор if, чтобы сказать, правильно или неправильно. Я пытаюсь передать команды программе, даже не печатая на клавиатуре. Есть смысл? Спасибо @abarnert - person RollingStone1234; 11.09.2014
comment
@RollingStone1234: mi.click() не вернет текст. Он вернется немедленно, ничего полезного. Затем, позже, когда пользователь говорит, текст будет вставлен в активный текстовый элемент управления. - person abarnert; 11.09.2014