ocrdesktop 41 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374
  1. #!/usr/bin/env python3
  2. # -*- coding: utf-8 -*-
  3. """OCRdesktop"""
  4. __version__ = "2.0"
  5. __copyright__ = "Copyright (c) 2015 Chrys"
  6. __license__ = "GPL"
  7. __authors__ = ["chrys"]
  8. __website__ = "https://github.com/chrys87/ocrdesktop"
  9. __appname__ = "OCRdesktop"
  10. __comments__ = "A accessibility tool for woring with inaccessible windows and dialogs"
  11. #Python Utils
  12. import os, sys, getopt, locale, time, re, _thread, shutil
  13. #PIL
  14. from PIL import Image
  15. from PIL import ImageOps
  16. #tesseract
  17. from tesserwrap import Tesseract
  18. #gi
  19. import gi
  20. #GTK/GDK/Wnck/GObject
  21. gi.require_version("Gtk", "3.0")
  22. gi.require_version("Gdk", "3.0")
  23. gi.require_version("Wnck", "3.0")
  24. from gi.repository import Gtk, Gdk, GObject, Wnck
  25. # AT-SPI
  26. gi.require_version('Atspi', '2.0')
  27. import pyatspi
  28. # here the class
  29. class OCRNavigation(Gtk.Window):
  30. def __init__(self, debug_p = False):
  31. self._debug = debug_p
  32. self._tree = None
  33. self._textbox = None
  34. self._textbuffer = None
  35. self._saveToMacroButton = None
  36. self._viewButton = None
  37. self._viewMode = 0
  38. self._keyboardOverlayActive = False
  39. self._screenShotMode = 0 # 0 = Window; 1 = Desktop
  40. self._sendToClipboard = False
  41. self._hideGui = False
  42. self._saveToMacro = False
  43. self._scrolledWindowTree = None
  44. self._scrolledWindowText = None
  45. self._keyboardOverlayLabel = None
  46. self._grid = None
  47. self._menubar = None
  48. self._font_button = None
  49. self._accelerators = None
  50. self._OCRWords = None
  51. self._OCRWordList = []
  52. self._OCRText = ''
  53. self._img = None
  54. self._modifiedImg = None
  55. self._grayscaleImg = False
  56. self._invertImg = False
  57. self._blackWhiteImg = False
  58. self._printToStdOut = False
  59. self._blackWhiteImgValue = 200
  60. self._scaleFactor = 3
  61. self._offsetXpos = 0
  62. self._offsetYpos = 0
  63. self.GTKmainIsRunning = False
  64. locale.setlocale(locale.LC_ALL, 'C') #needed by tesseract in non english languages
  65. self._macro = OCRMacroManager()
  66. self._languageCode = 'eng'
  67. self._tess = None
  68. self._isRefreshing = False
  69. def _setHideGui(self, hideGui_p = False):
  70. self.hideGui = hideGui_p
  71. def _setlanguageCode(self, languageCode_p = 'eng'):
  72. self._languageCode = languageCode_p
  73. def _setGrayscaleImg(self, grayscaleImg_p = False):
  74. self._grayscaleImg = grayscaleImg_p
  75. def _setInvertImg(self, invertImg_p = False):
  76. self._invertImg = invertImg_p
  77. def _setBlackWhiteImg(self, blackWhiteImg_p = False):
  78. self._blackWhiteImg = blackWhiteImg_p
  79. def _setBlackWhiteImgValue(self, blackWhiteImgValue_p = 200):
  80. self._blackWhiteImgValue = blackWhiteImgValue_p
  81. def _setPrintToStdOut(self, printToStdOut_p = False):
  82. self._printToStdOut = printToStdOut_p
  83. def _setSendToClipboard(self, sendToClipboard_p = False):
  84. self._sendToClipboard = sendToClipboard_p
  85. def _setScreenShotMode(self, screenShotMode_p):
  86. self._screenShotMode = screenShotMode_p
  87. def _setMacro(self, macro_p):
  88. self._macro = macro_p
  89. def _screenShotDesktop(self):
  90. CurrDesktop = Gdk.get_default_root_window()
  91. pixBuff = Gdk.pixbuf_get_from_window(CurrDesktop, 0, 0, CurrDesktop.get_width(), CurrDesktop.get_height())
  92. if (pixBuff != None):
  93. self._img = self.pixbuf2image(pixBuff)
  94. if self._debug: # Debug code
  95. self._img.save("/tmp/ocrScreenshot.png")
  96. print("save screenshot:/tmp/ocrScreenshot.png")
  97. self._scaleImg()
  98. return True
  99. else:
  100. if self._debug: # Debug code
  101. print("Could not take screenshot")
  102. return False
  103. def _screenShotWindow(self): #Mode=0 Desktop Mode=1 CurrWindow
  104. Gtk.main_iteration_do(False) # workarround segfault
  105. gdkCurrDesktop = Gdk.get_default_root_window()
  106. #currWindow = Gdk.gdk_screen_get_active_window(Gdk.gdk_screen_get_default())
  107. #pixBuff = Gdk.pixbuf_get_from_window(currWindow, 0, 0, currWindow.get_width(), currWindow.get_height())
  108. try:
  109. currWnckScreen = Wnck.Screen.get_default()
  110. currWnckScreen.force_update()
  111. currWnckWindow = currWnckScreen.get_active_window()
  112. self._offsetXpos, self._offsetYpos, wnckWidth, wnckHeight = Wnck.Window.get_geometry(currWnckWindow)
  113. pixBuff = Gdk.pixbuf_get_from_window(gdkCurrDesktop, self._offsetXpos, self._offsetYpos , wnckWidth, wnckHeight)
  114. except:
  115. return False
  116. if self._debug:
  117. pixBuff.savev('/tmp/ocrpixBuff.bmp', 'bmp', [], []) # Debug code
  118. print("save pixBuff /tmp/ocrpixBuff.bmp")
  119. if (pixBuff != None):
  120. self._img = self.pixbuf2image(pixBuff)
  121. if self._debug: # Debug code
  122. self._img.save("/tmp/ocrScreenshot.png")
  123. print("save screenshot:/tmp/ocrScreenshot.png")
  124. self._scaleImg()
  125. return True
  126. else:
  127. if self._debug: # Debug code
  128. print("Could not take screenshot")
  129. return False
  130. def pixbuf2image(self, pix):
  131. """Convert gdkpixbuf to PIL image"""
  132. data = pix.get_pixels()
  133. w = pix.props.width
  134. h = pix.props.height
  135. stride = pix.props.rowstride
  136. mode = "RGB"
  137. if pix.props.has_alpha == True:
  138. mode = "RGBA"
  139. im = Image.frombytes(mode, (w, h), data, "raw", mode, stride)
  140. return im
  141. def _scaleImg(self):
  142. width_screen, height_screen = self._img.size
  143. width_screen = width_screen * self._scaleFactor
  144. height_screen = height_screen * self._scaleFactor
  145. self._img = self._img.resize( (width_screen, height_screen), Image.BICUBIC)
  146. if self._debug: # Debug code
  147. self._img.save("/tmp/ocrScreenshotScaled.png")
  148. print("save scaled screenshot:/tmp/ocrScreenshotScaled.png")
  149. def _screenShot(self):
  150. Ok = False
  151. time.sleep(0.3)
  152. if self._screenShotMode == 0:
  153. try: #take care that we get a screenshot
  154. Ok = self._screenShotWindow()
  155. if not Ok:
  156. if self._debug:
  157. print('FALLBACK: was not able to Screenshot active window. Try Rootwindow now')
  158. Ok = self._screenShotDesktop()
  159. except:
  160. if self._debug:
  161. print('FALLBACK: was not able to Screenshot active window. Try Rootwindow now')
  162. Ok = self._screenShotDesktop()
  163. elif self._screenShotMode == 1:
  164. Ok = self._screenShotDesktop()
  165. return Ok
  166. def _ocrImage(self):
  167. if self._modifiedImg is None:
  168. return False
  169. if os.path.exists("/usr/share/tesseract-ocr/4.00/tessdata/"):
  170. tesseractData = "/usr/share/tesseract-ocr/4.00/tessdata/"
  171. elif os.path.exists("/usr/share/tesseract-ocr/tessdata/"):
  172. tesseractData = "/usr/share/tesseract-ocr/tessdata/"
  173. elif os.path.exists("/usr/share/tesseract/tessdata/"):
  174. tesseractData = "/usr/share/tesseract/tessdata/"
  175. elif os.path.exists("/usr/share/tessdata/"):
  176. tesseractData = "/usr/share/tessdata/"
  177. else:
  178. tesseractData = "/usr/share/"
  179. self._tess = Tesseract(tesseractData, self._languageCode)
  180. self._OCRText = self._tess.ocr_image(self._modifiedImg)
  181. regexSpace = re.compile('[^\S\r\n]{2,}') #remove double spaces
  182. self._OCRText = regexSpace.sub(' ',self._OCRText)
  183. regexSpace = re.compile('\n\s*\n') #remove empty lines
  184. self._OCRText = regexSpace.sub('\n',self._OCRText)
  185. regexSpace = re.compile('\s*\n') #remove ending spaces
  186. self._OCRText = regexSpace.sub('\n',self._OCRText)
  187. regexSpace = re.compile('\n\s') #remove trailing spaces
  188. self._OCRText = regexSpace.sub( '\n', self._OCRText)
  189. regexSpace = re.compile('^\s') #remove trailing space in first line
  190. self._OCRText = regexSpace.sub( '\n', self._OCRText)
  191. regexSpace = re.compile('$\n') #remove ending newline
  192. self._OCRText = regexSpace.sub( '', self._OCRText)
  193. if self._sendToClipboard:
  194. self._setTextToClipboard( self._OCRText)
  195. if self._printToStdOut:
  196. print(self._OCRText)
  197. if not self._hideGui:
  198. self._OCRWords = self._tess.get_words()
  199. self._fillOCRWordlist()
  200. return True
  201. def _fillOCRWordlist(self):
  202. for OCRWord in self._OCRWords: # fill the list
  203. if int(OCRWord.confidence) != 0:
  204. self._OCRWordList.append([OCRWord.value.decode("utf-8"),
  205. round((OCRWord.box[3] - OCRWord.box[1]) / 3 * 0.78,0),
  206. 'unknown',
  207. 'text',
  208. int((OCRWord.box[2] - OCRWord.box[0]) / 2 + OCRWord.box[0]),
  209. int((OCRWord.box[3] - OCRWord.box[1]) / 2 + OCRWord.box[1]),
  210. int(OCRWord.confidence)])
  211. def add_accelerator(self, widget, accelerator, signal="activate"):
  212. """Adds a keyboard shortcut"""
  213. if accelerator is not None:
  214. key, mod = Gtk.accelerator_parse(accelerator)
  215. widget.add_accelerator(signal, self._accelerators, key, mod, Gtk.AccelFlags.VISIBLE)
  216. def on_font_set(self, widget):
  217. font_description = widget.get_font_desc()
  218. self._textbox.modify_font(font_description)
  219. def _onRefreshContent(self, widget):
  220. self._refreshContent()
  221. def _transformImg(self):
  222. self._modifiedImg = self._img
  223. if self._invertImg:
  224. self._modifiedImg = ImageOps.invert(self._modifiedImg)
  225. if self._grayscaleImg:
  226. self._modifiedImg = ImageOps.grayscale(self._modifiedImg)
  227. if self._blackWhiteImg:
  228. lut = [255 if v > self._blackWhiteImgValue else 0 for v in range(256)]
  229. self._modifiedImg = self._modifiedImg.point(lut)
  230. if self._debug: # Debug code
  231. self._modifiedImg.save("/tmp/ocrScreenshotTransformed.png")
  232. print("save scaled screenshot:/tmp/ocrScreenshotTransformed.png")
  233. def _refreshContent(self):
  234. if self._isRefreshing == True:
  235. print("refresh already running")
  236. return
  237. self._isRefreshing = True
  238. if self._debug:
  239. print("refresh")
  240. self._tree = None
  241. self._OCRWords = None
  242. self._OCRWordList = []
  243. self._OCRText = ''
  244. self._scrolledWindowTree = None
  245. self._scrolledWindowText = None
  246. self._textbox = None
  247. self._transformImg()
  248. self._ocrImage()
  249. self._scrolledWindowText = Gtk.ScrolledWindow()
  250. self._textbox = Gtk.TextView()
  251. self._textbox.set_hexpand(True)
  252. self._textbox.set_vexpand(True)
  253. self._textbox.show()
  254. self._textbuffer = self._textbox.get_buffer()
  255. self._textbuffer.set_text(self._OCRText)
  256. self._textbox.set_editable(False)
  257. if not self._textbuffer.get_start_iter() is None:
  258. self._textbuffer.place_cursor(self._textbuffer.get_start_iter())
  259. self._scrolledWindowText.add(self._textbox)
  260. self._scrolledWindowTree = Gtk.ScrolledWindow()
  261. self._tree = Gtk.TreeView()
  262. self._tree.set_hexpand(True)
  263. self._tree.set_vexpand(True)
  264. self._tree.show()
  265. self._scrolledWindowTree.add(self._tree)
  266. cols = [GObject.TYPE_STRING]
  267. cols.extend([GObject.TYPE_STRING])
  268. cols.extend([GObject.TYPE_INT])
  269. cols.extend([GObject.TYPE_STRING])
  270. cols.extend([GObject.TYPE_STRING])
  271. cols.extend([GObject.TYPE_INT])
  272. cols.extend([GObject.TYPE_INT])
  273. cols.extend([GObject.TYPE_INT])
  274. model = Gtk.ListStore(*cols)
  275. self._tree.set_model(model)
  276. columnHeaders = ['OCR Text','Fontsize','Color','Object','X Position','Y Position','Confidence']
  277. cell = Gtk.CellRendererText()
  278. column = Gtk.TreeViewColumn("OCR Text", cell, text=0)
  279. column.set_visible(False)
  280. self._tree.append_column(column)
  281. for i, header in enumerate(columnHeaders):
  282. cell = Gtk.CellRendererText()
  283. column = Gtk.TreeViewColumn(header, cell, text=i+1)
  284. #column.set_sort_column_id(i+1)
  285. self._tree.append_column(column)
  286. model = self._tree.get_model()
  287. for row in self._OCRWordList:
  288. rowIter = model.append(None)
  289. i = 0
  290. for cell in row:
  291. i = i + 1
  292. if i == 5:
  293. cell = cell / self._scaleFactor + self._offsetXpos
  294. if i == 6:
  295. cell = cell / self._scaleFactor + self._offsetYpos
  296. # if i == 1:
  297. model.set_value(rowIter, i, cell)
  298. # i = i + 1
  299. # cell = 12
  300. # model.set_value(rowIter, i, cell)
  301. # i = i + 1
  302. # cell = 'black'
  303. # model.set_value(rowIter, i, cell)
  304. # else:
  305. # model.set_value(rowIter, i, cell)
  306. self._tree.set_search_column(1)
  307. self._grid.attach(self._scrolledWindowTree, 0, 1, 10, 10)
  308. self._grid.attach(self._scrolledWindowText, 0, 1, 10, 10)
  309. self._setView(False)
  310. self._isRefreshing = False
  311. def _onSendKey(self, event):
  312. eventTypeID = 0
  313. if self._debug:
  314. print("_onSendKey")
  315. print('Type:' + str(event.type))
  316. print('String: ' + event.event_string)
  317. print('ID: ' + str(event.id))
  318. print('hw_code: ' + str(event.hw_code))
  319. if event.type == pyatspi.Atspi.EventType.KEY_PRESSED_EVENT:
  320. if event.event_string =='F4':
  321. self._keyboardOverlayActive = False
  322. self._setView(False)
  323. pyatspi.Registry.deregisterKeystrokeListener(self._onSendKey)
  324. if self._debug:
  325. print('deregisterKeystrokeListener')
  326. return True
  327. eventTypeID = 0
  328. elif event.type == pyatspi.Atspi.EventType.KEY_RELEASED_EVENT:
  329. eventTypeID = 1
  330. self._macro._writeKeyboardToMacro(0, event.event_string, eventTypeID)
  331. return True
  332. def _sendKeyMode(self, widget):
  333. self._keyboardOverlayActive = True
  334. if self._debug:
  335. print("sendKeyMode")
  336. pyatspi.Registry.registerKeystrokeListener(self._onSendKey,mask=pyatspi.allModifiers(), kind=(pyatspi.KEY_PRESS,pyatspi.KEY_RELEASE,pyatspi.KEY_PRESSRELEASE), synchronous=True, preemptive=True)
  337. self._setView(False)
  338. if self._debug:
  339. print("Keyboardlistener is registered")
  340. def _toggleGrayscaleImg(self, widget):
  341. self._grayscaleImg = widget.get_active()
  342. if not self._grayscaleImg:
  343. self.item_barrierbw.set_active(False)
  344. def _toggleInvertImg(self, widget):
  345. self._invertImg = widget.get_active()
  346. def _toggleBlackWhiteImg(self, widget):
  347. self._blackWhiteImg = widget.get_active()
  348. if self._blackWhiteImg:
  349. self.item_grayscale.set_active(True)
  350. def _createNavListDialog(self):
  351. Gtk.Window.__init__(self, title="OCR")
  352. self.set_default_size(700,800)
  353. self._grid = Gtk.Grid()
  354. self._accelerators = Gtk.AccelGroup()
  355. self._menubar = Gtk.MenuBar()
  356. self.menu_ocrdesktop = Gtk.Menu()
  357. self.item_toggleview = Gtk.MenuItem("Toggle _View")
  358. self.item_toggleview.set_use_underline(True)
  359. self.add_accelerator(self.item_toggleview, "<Control>v","activate")
  360. self.item_ocroptions = Gtk.MenuItem("_OCR Options")
  361. self.item_ocroptions.set_use_underline(True)
  362. self.option_sub_menu = Gtk.Menu()
  363. self.item_ocroptions.set_submenu(self.option_sub_menu)
  364. self.item_invert = Gtk.CheckMenuItem("_Invert")
  365. self.item_invert.set_use_underline(True)
  366. self.item_grayscale = Gtk.CheckMenuItem("_Grayscale")
  367. self.item_grayscale.set_use_underline(True)
  368. self.item_barrierbw = Gtk.CheckMenuItem("_Barrier Black White")
  369. self.item_barrierbw.set_use_underline(True)
  370. self.option_sub_menu.append(self.item_invert)
  371. self.option_sub_menu.append(self.item_grayscale)
  372. self.option_sub_menu.append(self.item_barrierbw)
  373. self.item_invert.set_active(self._invertImg)
  374. self.item_grayscale.set_active(self._grayscaleImg)
  375. self.item_barrierbw.set_active(self._blackWhiteImg)
  376. self.item_invert.connect("activate", self._toggleInvertImg)
  377. self.item_grayscale.connect("activate", self._toggleGrayscaleImg)
  378. self.item_barrierbw.connect("activate", self._toggleBlackWhiteImg)
  379. self.item_retry = Gtk.MenuItem("_Retry OCR")
  380. self.item_retry.set_use_underline(True)
  381. self.add_accelerator(self.item_retry, "F5","activate")
  382. self.item_clipboard = Gtk.MenuItem("Send to _Clipboard")
  383. self.item_clipboard.set_use_underline(True)
  384. self.add_accelerator(self.item_clipboard, "<Control>b","activate")
  385. self.item_font = Gtk.MenuItem("_Font")
  386. self.item_font.set_use_underline(True)
  387. self.item_close = Gtk.MenuItem("_Close")
  388. self.add_accelerator(self.item_close, "<Control>q","activate")
  389. self.item_close.set_use_underline(True)
  390. self.menu_ocrdesktop.append(self.item_toggleview)
  391. self.menu_ocrdesktop.append(self.item_ocroptions)
  392. self.menu_ocrdesktop.append(self.item_retry)
  393. self.menu_ocrdesktop.append(self.item_clipboard)
  394. #self.menu_ocrdesktop.append(self.item_font)
  395. self.menu_ocrdesktop.append(self.item_close)
  396. self.item_toggleview.connect("activate", self._onSetView,True)
  397. self.item_retry.connect("activate", self._onRefreshContent)
  398. self.item_clipboard.connect("activate", self._onSetTextToClipboard)
  399. self.item_close.connect("activate", Gtk.main_quit)
  400. self.menu_interact = Gtk.Menu()
  401. self.item_preclick = Gtk.CheckMenuItem("_Preclick")
  402. self.item_preclick.set_use_underline(True)
  403. self.add_accelerator(self.item_preclick, "<Control>p","activate")
  404. self.item_leftclick = Gtk.MenuItem("_Left Click")
  405. self.item_leftclick.set_use_underline(True)
  406. self.add_accelerator(self.item_leftclick, "<Control>l","activate")
  407. self.item_doubletclick = Gtk.MenuItem("_Double Click")
  408. self.item_doubletclick.set_use_underline(True)
  409. self.add_accelerator(self.item_doubletclick, "<Control>d","activate")
  410. self.item_rightclick = Gtk.MenuItem("_Right Click")
  411. self.item_rightclick.set_use_underline(True)
  412. self.add_accelerator(self.item_rightclick, "<Control>r","activate")
  413. self.item_middleclick = Gtk.MenuItem("_Middle Click")
  414. self.item_middleclick.set_use_underline(True)
  415. self.add_accelerator(self.item_middleclick, "<Control>m","activate")
  416. self.item_routeto = Gtk.MenuItem("Route _To")
  417. self.item_routeto.set_use_underline(True)
  418. self.add_accelerator(self.item_routeto, "<Control>t","activate")
  419. self.item_sendkey = Gtk.MenuItem("Send _Key")
  420. self.item_sendkey.set_use_underline(True)
  421. self.add_accelerator(self.item_sendkey, "<Control>k","activate")
  422. self.menu_interact.append(self.item_preclick)
  423. self.menu_interact.append(self.item_leftclick)
  424. self.menu_interact.append(self.item_doubletclick)
  425. self.menu_interact.append(self.item_rightclick)
  426. self.menu_interact.append(self.item_middleclick)
  427. self.menu_interact.append(self.item_routeto)
  428. self.menu_interact.append(self.item_sendkey)
  429. self.item_preclick.connect("activate", self._setSaveToMacro)
  430. self.item_leftclick.connect("activate", self._onLeftClick)
  431. self.item_doubletclick.connect("activate", self._onDoubleLeftClick)
  432. self.item_rightclick.connect("activate", self._onRightClick)
  433. self.item_middleclick.connect("activate", self._onMiddleClick)
  434. self.item_routeto.connect("activate", self._routeToPoint)
  435. self.item_sendkey.connect("activate", self._sendKeyMode)
  436. self.menu_macro = Gtk.Menu()
  437. self.item_save = Gtk.MenuItem("_Save As")
  438. self.item_save.set_use_underline(True)
  439. self.add_accelerator(self.item_save, "<Control>s","activate")
  440. self.item_load = Gtk.MenuItem("_Load")
  441. self.item_load.set_use_underline(True)
  442. self.add_accelerator(self.item_load, "<Control>o","activate")
  443. self.item_delete = Gtk.MenuItem("_Unload")
  444. self.item_delete.set_use_underline(True)
  445. self.add_accelerator(self.item_delete, "<Control>u","activate")
  446. self.item_run = Gtk.MenuItem("_Run")
  447. self.item_run.set_use_underline(True)
  448. self.add_accelerator(self.item_run, "<Control>n","activate")
  449. self.menu_macro.append(self.item_save)
  450. self.menu_macro.append(self.item_load)
  451. self.menu_macro.append(self.item_delete)
  452. self.menu_macro.append(self.item_run)
  453. self.item_save.connect("activate", self._macro._saveMacro, self)
  454. self.item_load.connect("activate", self._macro._onLoadMacro, self)
  455. self.item_delete.connect("activate", self._macro._onDeleteMacro, False)
  456. self.item_run.connect("activate", self._onRunMacro)
  457. self.menu_help = Gtk.Menu()
  458. self.item_about = Gtk.MenuItem("_About")
  459. self.item_about.set_use_underline(True)
  460. self.menu_help.append(self.item_about)
  461. self.item_about.connect("activate", self._onRunAboutDialog, self)
  462. self.item_ocrdesktop = Gtk.MenuItem("_OCRDesktop")
  463. self.item_ocrdesktop.set_use_underline(True)
  464. self.item_interact = Gtk.MenuItem("_Interact")
  465. self.item_interact.set_use_underline(True)
  466. self.item_macro = Gtk.MenuItem("_Macro")
  467. self.item_macro.set_use_underline(True)
  468. self.item_help = Gtk.MenuItem("_Help")
  469. self.item_help.set_use_underline(True)
  470. self.item_ocrdesktop.set_submenu(self.menu_ocrdesktop)
  471. self.item_interact.set_submenu(self.menu_interact)
  472. self.item_macro.set_submenu(self.menu_macro)
  473. self.item_help.set_submenu(self.menu_help)
  474. self._menubar.append(self.item_ocrdesktop)
  475. self._menubar.append(self.item_interact)
  476. self._menubar.append(self.item_macro)
  477. self._menubar.append(self.item_help)
  478. self.add_accel_group(self._accelerators)
  479. self._keyboardOverlayLabel = Gtk.Label("Please insert keyboard commands. exit with: F4")
  480. self._keyboardOverlayLabel.set_selectable(True)
  481. self._font_button = Gtk.FontButton()
  482. self._font_button.connect('font-set', self.on_font_set)
  483. self._refreshContent()
  484. self.connect("delete-event", Gtk.main_quit)
  485. self.connect('key-release-event', self._onKeyRelease)
  486. #self._textbuffer.connect("notify::cursor-position", self._onCursorTextPositionChanged)
  487. #self._tree.connect("notify::cursor-position", self._onCursorTreePositionChanged)
  488. self._grid.attach(self._menubar,0,0,10,1)
  489. self._grid.attach(self._keyboardOverlayLabel, 0, 1, 10, 1)
  490. self._grid.attach(self._font_button, 0, 11, 3, 1)
  491. self.add(self._grid)
  492. def _onCursorTextPositionChanged(self, widget, event):
  493. #print(widget.props.cursor_position)
  494. #position = widget.get_iter_at_offset(widget.props.cursor_position)
  495. #if not widget.get_start_iter() is None:
  496. # print(widget.get_text(widget.get_start_iter(),position,False).count('\n')+widget.get_text(widget.get_start_iter(),position,True).count(' '))
  497. #TODO set the pos correct
  498. #wtf is thist not working self._tree.set_cursor(widget.get_text(widget.get_start_iter(),position,True).count('\n')+widget.get_text(widget.get_start_iter(),position,True).count(' '))
  499. pass
  500. def _onCursorTreePositionChanged(self, widget, event):
  501. #TODO set the pos correct
  502. #print(widget.props.cursor_position)
  503. #position = widget.get_iter_at_offset(widget.props.cursor_position)
  504. #if not widget.get_start_iter() is None:
  505. # print(widget.get_text(widget.get_start_iter(),position,False).count('\n')+widget.get_text(widget.get_start_iter(),position,True).count(' '))
  506. # self._tree.set_cursor(widget.get_text(widget.get_start_iter(),position,True).count('\n')+widget.get_text(widget.get_start_iter(),position,True).count(' '))
  507. pass
  508. def _setSaveToMacro(self, widget):
  509. self._saveToMacro = widget.get_active()
  510. def setFocus(self):
  511. if self._viewMode == 0:
  512. position = self._textbuffer.get_iter_at_offset(self._textbuffer.props.cursor_position)
  513. if not self._textbuffer.get_start_iter() is None:
  514. self._tree.set_cursor(self._textbuffer.get_text(self._textbuffer.get_start_iter(),position,True).count('\n')+self._textbuffer.get_text(self._textbuffer.get_start_iter(),position,True).count(' '))
  515. def showGUI(self):
  516. self._gui = self._createNavListDialog()
  517. self.set_modal(True)
  518. self.show_all()
  519. self._setView(False)
  520. self.startMain()
  521. def startMain(self):
  522. self.GTKmainIsRunning = True
  523. Gtk.main()
  524. def _onRunAboutDialog(self,widget,window):
  525. dialog = Gtk.AboutDialog(window)
  526. dialog.set_authors(__authors__)
  527. dialog.set_website(__website__)
  528. dialog.set_copyright(__copyright__)
  529. dialog.set_license(__license__)
  530. dialog.set_version(__version__)
  531. dialog.set_program_name(__appname__)
  532. dialog.set_comments(__comments__)
  533. dialog.run()
  534. dialog.destroy()
  535. def _onSetView(self, widget, Toggle=True):
  536. self._setView(Toggle)
  537. def _setView(self, Toggle):
  538. self._scrolledWindowTree.hide()
  539. self._scrolledWindowText.hide()
  540. self._keyboardOverlayLabel.hide()
  541. if self._keyboardOverlayActive:
  542. self._keyboardOverlayLabel.show()
  543. return
  544. self.setFocus()
  545. if Toggle:
  546. if self._viewMode == 0:
  547. self._viewMode = 1
  548. elif self._viewMode == 1:
  549. self._viewMode = 0
  550. if self._viewMode == 1:
  551. self._scrolledWindowTree.show()
  552. self._tree.grab_focus()
  553. elif self._viewMode == 0:
  554. self._scrolledWindowText.show()
  555. self._textbox.grab_focus()
  556. def _onKeyRelease(self, widget, event):
  557. keycode = event.hardware_keycode
  558. keymap = Gdk.Keymap.get_default()
  559. entries_for_keycode = keymap.get_entries_for_keycode(keycode)
  560. entries = entries_for_keycode[-1]
  561. eventString = Gdk.keyval_name(entries[0])
  562. # if self._debug:
  563. # print(eventString)
  564. # if eventString == 'Escape':
  565. # Gtk.main_quit()
  566. # if eventString == 'Return':
  567. # self._leftClickButton.grab_focus()
  568. def _cancel(self):
  569. if self.GTKmainIsRunning:
  570. Gtk.main_quit()
  571. GTKmainIsRunning = False
  572. def _routeToPoint(self, widget):
  573. self.setFocus()
  574. self.hide()
  575. xpos, ypos = self._getSelectedEntry()
  576. _thread.start_new_thread( self._threadrouteToPoint, (xpos,ypos, ) )
  577. def _onRightClick(self, widget):
  578. self.setFocus()
  579. xpos, ypos = self._getSelectedEntry()
  580. self.hide()
  581. _thread.start_new_thread( self._threadDoClick, (xpos,ypos,"b3c", ) )
  582. def _onLeftClick(self, widget):
  583. self.setFocus()
  584. xpos, ypos = self._getSelectedEntry()
  585. self.hide()
  586. _thread.start_new_thread( self._threadDoClick, (xpos,ypos, "b1c", ) )
  587. def _onDoubleLeftClick(self, widget):
  588. self.setFocus()
  589. xpos, ypos = self._getSelectedEntry()
  590. self.hide()
  591. _thread.start_new_thread( self._threadDoClick, (xpos,ypos,"b1d", ) )
  592. def _onMiddleClick(self, widget):
  593. self.setFocus()
  594. xpos, ypos = self._getSelectedEntry()
  595. self.hide()
  596. _thread.start_new_thread( self._threadDoClick, (xpos,ypos,"b2c", ) )
  597. def _threadrouteToPoint(self, xpos=1,ypos=1,delay=0.8, posRelation = "abs"):
  598. if self._saveToMacro:
  599. self._macro._writeMouseToMacro(xpos,ypos,'None')
  600. else:
  601. time.sleep(delay)
  602. pyatspi.Registry.generateMouseEvent(xpos,ypos,posRelation)
  603. self._cancel()
  604. def _onRunMacro(self, widget):
  605. if self._macro._macroExists():
  606. self.hide()
  607. _thread.start_new_thread( self._threadRunMacro, () )
  608. else:
  609. dialog = Gtk.MessageDialog(self, 0, Gtk.MessageType.INFO,
  610. Gtk.ButtonsType.OK, "No Macro loaded")
  611. dialog.format_secondary_text(
  612. "You have to load a macro for execution.")
  613. dialog.run()
  614. dialog.destroy()
  615. def _threadRunMacro(self):
  616. self._macro._threadRunMacro()
  617. self._cancel()
  618. def _threadDoClick(self, xpos=1,ypos=1,mouseEvent='b1c',delay=0.8):
  619. if self._saveToMacro:
  620. self._macro._writeMouseToMacro(xpos,ypos,mouseEvent)
  621. else:
  622. time.sleep(delay)
  623. pyatspi.Registry.generateMouseEvent(xpos,ypos, mouseEvent)
  624. self._cancel()
  625. def _onSetTextToClipboard(self, widget):
  626. self._setTextToClipboard(self._OCRText)
  627. def _setTextToClipboard(self, text_p):
  628. if self._debug:
  629. print("----_setTextToClipboard Start--")
  630. print(text_p)
  631. print("----_setTextToClipboard End----")
  632. ClipboardObj = Gtk.Clipboard.get(Gdk.SELECTION_CLIPBOARD)
  633. ClipboardObj.set_text(text_p, -1)
  634. ClipboardObj.store()
  635. def _getSelectedEntry(self):
  636. if not self._tree:
  637. return None
  638. selection = self._tree.get_selection()
  639. if not selection:
  640. return None
  641. model, paths = selection.get_selected_rows()
  642. if not paths:
  643. return None
  644. return model.get_value(model.get_iter(paths[0]), 5),model.get_value(model.get_iter(paths[0]), 6)
  645. class OCRScreenReader():
  646. def __init__(self):
  647. self._sendToClipboard = False
  648. self._hideGui = False
  649. self._screenShotMode = 0 # 0 = Window; 1 = Desktop
  650. self._macroFile = os.path.expanduser('~') + '/.activeOCRMacro.ocrm'
  651. self._showHelp = False
  652. self._debug = False
  653. self._languageCode = 'eng'
  654. self._grayscaleImg = False
  655. self._invertImg = False
  656. self._blackWhiteImg = False
  657. self._blackWhiteImgValue = 200
  658. self._printToStdOut = False
  659. self._setCommandLineOptions()
  660. if self._showHelp:
  661. return
  662. #MACRO
  663. self._macro = OCRMacroManager(self._debug)
  664. self._macro._loadMcroFile(self._macroFile)
  665. if not self._hideGui:
  666. self._macro.showGUI()
  667. else:
  668. if self._macro._macroExists():
  669. self._macro._RunMacro()
  670. #NAVIGATION
  671. self._Navigation = OCRNavigation(self._debug)
  672. self._Navigation._setlanguageCode(self._languageCode)
  673. self._Navigation._setGrayscaleImg(self._grayscaleImg)
  674. self._Navigation._setInvertImg(self._invertImg)
  675. self._Navigation._setBlackWhiteImg(self._blackWhiteImg)
  676. self._Navigation._setBlackWhiteImgValue(self._blackWhiteImgValue)
  677. self._Navigation._setSendToClipboard(self._sendToClipboard)
  678. self._Navigation._setScreenShotMode(self._screenShotMode)
  679. self._Navigation._setHideGui(self._hideGui)
  680. self._Navigation._setPrintToStdOut(self._printToStdOut)
  681. if self._debug:
  682. print("PreWaitForFinish")
  683. self._macro.WaitForFinish()
  684. self._Navigation._setMacro(self._macro)
  685. time.sleep(0.5)
  686. if self._Navigation._screenShot():
  687. if not self._hideGui:
  688. self._Navigation.showGUI()
  689. else:
  690. self._Navigation._transformImg()
  691. self._Navigation._ocrImage()
  692. #FUNCTIONS
  693. def _setCommandLineOptions(self):
  694. try:
  695. myopts, args = getopt.getopt(sys.argv[1:],"hl:vndocgibt:m:")
  696. ###############################
  697. # o == option
  698. # a == argument passed to the o
  699. ###############################
  700. for o, a in myopts:
  701. if o == '-v':
  702. self._debug = True
  703. print('Debugmode ON')
  704. elif o == '-d':
  705. self._screenShotMode = 1
  706. elif o == '-g':
  707. self._grayscaleImg = True
  708. elif o == '-i':
  709. self._invertImg = True
  710. elif o == '-b':
  711. self._grayscaleImg = True
  712. self._blackWhiteImg = True
  713. elif o == '-t':
  714. self._blackWhiteImgValue = int(a)
  715. elif o == '-c':
  716. self._sendToClipboard = True
  717. elif o == '-l':
  718. self._languageCode = a
  719. elif o == '-m':
  720. self._macroFile = a
  721. elif o == '-n':
  722. self._hideGui = True
  723. elif o == '-o':
  724. self._printToStdOut = True
  725. elif o == '-h':
  726. self._printHelp()
  727. except:
  728. self._printHelp()
  729. def _printHelp(self):
  730. print(__version__)
  731. print("ocrdesktop -h -l -p -n -d -c -o -i -g -b -t -m")
  732. print("-h Print help with start")
  733. print("-l <lang> set the OCR language default=eng")
  734. print("-n hide GUI (use with -c,-o or -m")
  735. print("-o print to STDOUT")
  736. print("-v print debug messages")
  737. print("-d OCR the Destkop")
  738. print("-c Send to Clipboard")
  739. print("-i Invert the picture colors")
  740. print("-g Grayscale picture")
  741. print("-b break into hard black and white")
  742. print("-t the value for braking into black and white (-b) 0 (black) - 255 (white)")
  743. print("-m <MacroFile> run a macro before starting.")
  744. self._showHelp = True
  745. class OCRMacroManager:
  746. def __init__(self,debug_p = False):
  747. self._cancelButton = None
  748. self._runMacroButton = None
  749. self._deleteMacroButton = None
  750. self._menubar = None
  751. self._accelerators = None
  752. self._grid = None
  753. self._labelAutoClickExists = None
  754. self._macroFile = os.path.expanduser('~') + '/.activeOCRMacro.ocrm'
  755. self._gui = None
  756. self._MacroFinished = False
  757. self._debug = debug_p
  758. def _loadMcroFile(self, macroFile_p):
  759. if self._loadMacroExists(macroFile_p):
  760. if macroFile_p != self._macroFile:
  761. shutil.copy(macroFile_p, self._macroFile)
  762. def _setDebug(self, debug_p):
  763. self._debug = debug_p
  764. def add_accelerator(self, widget, accelerator, signal="activate"):
  765. """Adds a keyboard shortcut"""
  766. if accelerator is not None:
  767. key, mod = Gtk.accelerator_parse(accelerator)
  768. widget.add_accelerator(signal, self._accelerators, key, mod, Gtk.AccelFlags.VISIBLE)
  769. def _createMacroConfirm(self):
  770. dialog = Gtk.Window( title="Preclicks Manager")
  771. dialog.set_default_size(500, 60)
  772. dialog.set_modal(True)
  773. self._accelerators = Gtk.AccelGroup()
  774. self._menubar = Gtk.MenuBar()
  775. self._menubar = Gtk.MenuBar()
  776. self.menu_macro = Gtk.Menu()
  777. self.item_save = Gtk.MenuItem("_Save As")
  778. self.item_save.set_use_underline(True)
  779. self.add_accelerator(self.item_save, "<Control>s","activate")
  780. self.item_load = Gtk.MenuItem("_Load")
  781. self.item_load.set_use_underline(True)
  782. self.add_accelerator(self.item_load, "<Control>o","activate")
  783. self.item_delete = Gtk.MenuItem("_Unload")
  784. self.item_delete.set_use_underline(True)
  785. self.add_accelerator(self.item_delete, "<Control>u","activate")
  786. self.item_run = Gtk.MenuItem("_Run")
  787. self.item_run.set_use_underline(True)
  788. self.add_accelerator(self.item_run, "<Control>n","activate")
  789. self.menu_macro.append(self.item_save)
  790. self.menu_macro.append(self.item_load)
  791. self.menu_macro.append(self.item_delete)
  792. self.menu_macro.append(self.item_run)
  793. self.item_save.connect("activate", self._saveMacro, dialog)
  794. self.item_load.connect("activate", self._onLoadMacro, dialog)
  795. self.item_delete.connect("activate", self._onDeleteMacro, False)
  796. self.item_run.connect("activate", self._onRunMacro)
  797. self.menu_help = Gtk.Menu()
  798. self.item_about = Gtk.MenuItem("_About")
  799. self.item_about.set_use_underline(True)
  800. self.menu_help.append(self.item_about)
  801. self.item_about.connect("activate", self._onRunAboutDialog, dialog)
  802. self.item_macro = Gtk.MenuItem("_Macro")
  803. self.item_macro.set_use_underline(True)
  804. self.item_help = Gtk.MenuItem("_Help")
  805. self.item_help.set_use_underline(True)
  806. self.item_macro.set_submenu(self.menu_macro)
  807. self.item_help.set_submenu(self.menu_help)
  808. self._menubar.append(self.item_macro)
  809. self._menubar.append(self.item_help)
  810. dialog.add_accel_group(self._accelerators)
  811. self._labelAutoClickExists = Gtk.Label("Preclicks are existing. What do you want do do with the preclicks?")
  812. self._labelAutoClickExists.set_selectable(True)
  813. self._runMacroButton = Gtk.Button(label="_Run")
  814. self._runMacroButton.set_use_underline(True)
  815. self._runMacroButton.connect('clicked', self._onRunMacro)
  816. self._deleteMacroButton = Gtk.Button(label='_Unload')
  817. self._deleteMacroButton.set_use_underline(True)
  818. self._deleteMacroButton.connect('clicked', self._onDeleteMacro)
  819. self._cancelButton = Gtk.Button(label='_Cancel')
  820. self._cancelButton.set_use_underline(True)
  821. self._cancelButton.connect('clicked', self._onCancel)
  822. self._grid = Gtk.Grid()
  823. dialog.connect("delete-event", self._onCancel)
  824. dialog.connect('key-release-event', self._onKeyRelease)
  825. self._grid.attach(self._menubar,0,0,3,1)
  826. self._grid.attach(self._labelAutoClickExists, 0 , 1, 3, 1)
  827. self._grid.attach(self._runMacroButton , 0, 2, 1, 1)
  828. self._grid.attach(self._deleteMacroButton, 1, 2, 1, 1)
  829. self._grid.attach(self._cancelButton, 2, 2, 1, 1)
  830. dialog.add(self._grid)
  831. return dialog
  832. def _onRunMacro(self, widget):
  833. self._gui.hide()
  834. _thread.start_new_thread( self._threadRunMacro, () )
  835. self._cancel(False)
  836. def _onDeleteMacro(self, widget, close_p=True):
  837. self._deleteMacro()
  838. if close_p:
  839. self._cancel(True)
  840. def _onCancel(self, widget, event=None):
  841. self._cancel(True)
  842. def _cancel(self, setMacroFinished):
  843. if self._gui != None:
  844. self._gui.hide()
  845. if setMacroFinished:
  846. self._MacroFinished = True
  847. Gtk.main_quit()
  848. def _macroExists(self):
  849. return (os.path.exists(self._macroFile) and os.path.isfile(self._macroFile))
  850. def _loadMacroExists(self, newMacro_p):
  851. return (os.path.exists(newMacro_p) and os.path.isfile(newMacro_p))
  852. def _RunMacro(self):
  853. if not self._macroExists():
  854. if self._debug:
  855. print("No Macro loaded..")
  856. return
  857. self._MacroFinished = False
  858. macroFile = open(self._macroFile, "r")
  859. while 1:
  860. line = macroFile.readline()
  861. if not line:
  862. break
  863. if self._debug:
  864. print("_RunMacro: " + line)
  865. line = line.split(',')
  866. # doing stuff
  867. if line[0] == 'c':
  868. if line[1] == 'delay':
  869. time.sleep(float(line[2]))
  870. if line[0] == 'k':
  871. self._doKeyboardMacroStep(int(line[1]), line[2], int(line[3]))
  872. if line[0] == 'm':
  873. self._doMouseMacroStep(int(line[1]), int(line[2]), line[3])
  874. macroFile.close()
  875. self._MacroFinished = True
  876. def getMacroFinished(self):
  877. return self._MacroFinished
  878. def WaitForFinish(self):
  879. while not self.getMacroFinished() and self._macroExists():
  880. time.sleep(0.3)
  881. if self._debug:
  882. print(self.getMacroFinished())
  883. time.sleep(0.2)
  884. self._MacroFinished = False
  885. if self._debug:
  886. print("WaitForFinish complete")
  887. def _deleteMacro(self):
  888. if self._macroExists():
  889. os.remove(self._macroFile)
  890. def _saveMacro(self, widget, window):
  891. if not self._macroExists():
  892. return
  893. fileDialog = Gtk.FileChooserDialog("Save As", window,Gtk.FileChooserAction.SAVE,("_Cancel",Gtk.ResponseType.CANCEL,"_Save",Gtk.ResponseType.OK))
  894. fileDialog.set_modal(True)
  895. fileDialog.set_default_size(800, 400)
  896. fileDialog.set_local_only(False)
  897. self.add_filters(fileDialog)
  898. Gtk.FileChooser.set_current_name(fileDialog, "NewOCRdesktopMakro.ocrm")
  899. response = fileDialog.run()
  900. if response == Gtk.ResponseType.OK:
  901. shutil.copy( self._macroFile, fileDialog.get_filename(),)
  902. elif response == Gtk.ResponseType.CANCEL:
  903. pass
  904. fileDialog.destroy()
  905. def _onRunAboutDialog(self,widget,window):
  906. dialog = Gtk.AboutDialog(window)
  907. dialog.set_authors(__authors__)
  908. dialog.set_website(__website__)
  909. dialog.set_copyright(__copyright__)
  910. dialog.set_license(__license__)
  911. dialog.set_version(__version__)
  912. dialog.set_program_name(__appname__)
  913. dialog.set_comments(__comments__)
  914. dialog.run()
  915. dialog.destroy()
  916. def _onLoadMacro(self, widget, window):
  917. fileDialog = Gtk.FileChooserDialog("Please choose a file", window,Gtk.FileChooserAction.OPEN,("_Cancel",Gtk.ResponseType.CANCEL,"_Open",Gtk.ResponseType.OK))
  918. fileDialog.set_modal(True)
  919. fileDialog.set_default_size(800, 400)
  920. fileDialog.set_local_only(False)
  921. self.add_filters(fileDialog)
  922. response = fileDialog.run()
  923. if response == Gtk.ResponseType.OK:
  924. shutil.copy(fileDialog.get_filename(), self._macroFile)
  925. elif response == Gtk.ResponseType.CANCEL:
  926. pass
  927. fileDialog.destroy()
  928. def add_filters(self, fileDialog):
  929. filter_text = Gtk.FileFilter()
  930. filter_text.set_name("Macro Textfiles")
  931. filter_text.add_mime_type("text/plain")
  932. filter_text.add_pattern("*.ocrm")
  933. fileDialog.add_filter(filter_text)
  934. filter_any = Gtk.FileFilter()
  935. filter_any.set_name("Any files")
  936. filter_any.add_pattern("*")
  937. fileDialog.add_filter(filter_any)
  938. def _doKeyboardMacroStep(self,keyValue_p, keyString_p, eventType_p = 2):
  939. """
  940. Arguments:
  941. - keyValue_p: a long integer indicating the keycode or keysym of the key event
  942. being synthesized.
  943. - keyString_p: an (optional) UTF-8 string which, if keyval is NULL,
  944. indicates a 'composed' keyboard input string which is
  945. being synthesized; this type of keyboard event synthesis does
  946. not emulate hardware keypresses but injects the string
  947. as though a composing input method (such as XIM) were used.
  948. - eventType_p: an AccessibleKeySynthType flag indicating whether keyval
  949. is to be interpreted as a keysym rather than a keycode
  950. (pyatspi.KEY_SYM), or whether to synthesize
  951. KEY_PRESS = 0, KEY_RELEASE = 1, or both (KEY_PRESSRELEASE = 2).
  952. """
  953. if keyValue_p == 0:
  954. if keyString_p != '':
  955. keyValue_p = KEY_CODE[keyString_p]
  956. else:
  957. if self._debug:
  958. print("invalid keyboard macro",keyValue_p,keyString_p)
  959. print("format:")
  960. print("c, KeyValue, KeyString, eventType")
  961. return
  962. if eventType_p == 0:
  963. pyatspi.Registry.generateKeyboardEvent(keyValue_p, keyString_p, pyatspi.KEY_PRESS)
  964. elif eventType_p == 1:
  965. pyatspi.Registry.generateKeyboardEvent(keyValue_p, keyString_p, pyatspi.KEY_RELEASE)
  966. elif eventType_p == 2:
  967. pyatspi.Registry.generateKeyboardEvent(keyValue_p, keyString_p, pyatspi.KEY_PRESSRELEASE)
  968. def _doMouseMacroStep(self,xpos, ypos, mouseEvent, posRelation = "abs"):
  969. pyatspi.Registry.generateMouseEvent(xpos,ypos,posRelation)
  970. if (mouseEvent != 'None'):
  971. pyatspi.Registry.generateMouseEvent(xpos,ypos,mouseEvent)
  972. def _threadRunMacro(self):
  973. if self._debug:
  974. print("_threadRunMacro starts")
  975. self._RunMacro()
  976. def _writeKeyboardToMacro(self,keyValue_p, keyString_p, eventType_p):
  977. if eventType_p == pyatspi.KEY_PRESS:
  978. eventTypeID = 0
  979. elif eventType_p == pyatspi.KEY_RELEASE:
  980. eventTypeID = 1
  981. elif eventType_p == pyatspi.KEY_PRESSRELEASE:
  982. eventTypeID = 2
  983. macroFile = open(self._macroFile, "a")
  984. macroFile.write('k,' + str(keyValue_p) + ',' + str(keyString_p) + ',' + str(eventTypeID) + '\n')
  985. macroFile.close()
  986. def _writeMouseToMacro(self, Xpos_p, Ypos_p, MouseEvent_p):
  987. macroFile = open(self._macroFile, "a")
  988. macroFile.write('c,' + 'delay' + ',0.9\n')
  989. macroFile.write('m,' + str(Xpos_p) + ',' + str(Ypos_p) + ',' + MouseEvent_p + '\n')
  990. macroFile.close()
  991. def showGUI(self):
  992. if not self._macroExists():
  993. return
  994. self._gui = self._createMacroConfirm()
  995. self._gui.show_all()
  996. ts = Gtk.get_current_event_time()
  997. self._gui.present_with_time(ts)
  998. self._runMacroButton.grab_focus()
  999. Gtk.main()
  1000. def _onKeyRelease(self, widget, event):
  1001. keycode = event.hardware_keycode
  1002. keymap = Gdk.Keymap.get_default()
  1003. entries_for_keycode = keymap.get_entries_for_keycode(keycode)
  1004. entries = entries_for_keycode[-1]
  1005. eventString = Gdk.keyval_name(entries[0])
  1006. # if self._debug:
  1007. # print(eventString)
  1008. # if eventString == 'Escape':
  1009. # self._cancel(True)
  1010. # if eventString == 'Return':
  1011. # self._leftClickButton.grab_focus()
  1012. KEY_CODE = {
  1013. '¼':13,
  1014. '½':14,
  1015. '0':19,
  1016. '!':10,
  1017. '/':106,
  1018. '"':11,
  1019. '1':10,
  1020. '¹':10,
  1021. '§':12,
  1022. '$':13,
  1023. '%':14,
  1024. '¬':15,
  1025. '&':15,
  1026. '/':16,
  1027. '{':16,
  1028. '(':17,
  1029. '[':17,
  1030. ')':18,
  1031. ']':18,
  1032. '=':19,
  1033. '}':19,
  1034. '?':20,
  1035. '\\':20,
  1036. '2':11,
  1037. '²':11,
  1038. '@':24,
  1039. '€':26,
  1040. '¶':27,
  1041. '←':29,
  1042. '↓':30,
  1043. '→':31,
  1044. '3':12,
  1045. '³':12,
  1046. '~':35,
  1047. '*':35,
  1048. '+':35,
  1049. '':37,
  1050. '4':13,
  1051. '°':49,
  1052. '′':49,
  1053. "'":51,
  1054. '#':51,
  1055. '5':14,
  1056. '»':52,
  1057. '«':53,
  1058. '¢':54,
  1059. '„':55,
  1060. '“':56,
  1061. '”':57,
  1062. 'µ':58,
  1063. ',':59,
  1064. ';':59,
  1065. '·':59,
  1066. ':':60,
  1067. '.':60,
  1068. '…':60,
  1069. '_':61,
  1070. '-':61,
  1071. '–':61,
  1072. '6':15,
  1073. '*':63,
  1074. '7':16,
  1075. '7':79,
  1076. '8':17,
  1077. '-':82,
  1078. '+':86,
  1079. '':9,
  1080. '9':18,
  1081. '<':94,
  1082. '>':94,
  1083. '|':94,
  1084. 'a':38,
  1085. 'A':38,
  1086. 'ä':48,
  1087. 'Ä':48,
  1088. 'Alt_L':64,
  1089. 'b':56,
  1090. 'B':56,
  1091. 'BackSpace':22,
  1092. 'c':54,
  1093. 'C':54,
  1094. 'Caps_Lock':66,
  1095. 'd':40,
  1096. 'D':40,
  1097. 'đ':41,
  1098. 'dead_acute':21,
  1099. 'dead_cedilla':21,
  1100. 'dead_circumflex':49,
  1101. 'dead_diaeresis':34,
  1102. 'dead_grave':21,
  1103. 'Delete':119,
  1104. 'Down':116,
  1105. 'e':26,
  1106. 'E':26,
  1107. 'End':115,
  1108. 'Escape':9,
  1109. 'F10':76,
  1110. 'F11':95,
  1111. 'F12':96,
  1112. 'F1':67,
  1113. 'F2':68,
  1114. 'F3':69,
  1115. 'f':41,
  1116. 'F':41,
  1117. 'F4':70,
  1118. 'F5':71,
  1119. 'F6':72,
  1120. 'F7':73,
  1121. 'F8':74,
  1122. 'F9':75,
  1123. 'g':42,
  1124. 'G':42,
  1125. 'h':43,
  1126. 'H':43,
  1127. 'Home':110,
  1128. 'i':31,
  1129. 'I':31,
  1130. 'Insert':118,
  1131. 'ISO_Left_Tab':23,
  1132. 'ISO_Level3_Shift':108,
  1133. 'j':44,
  1134. 'J':44,
  1135. 'k':45,
  1136. 'K':45,
  1137. 'KP_Begin':84,
  1138. 'KP_Delete':91,
  1139. 'KP_Down':88,
  1140. 'KP_End':87,
  1141. 'KP_Enter':104,
  1142. 'KP_Home':79,
  1143. 'KP_Insert':90,
  1144. 'KP_Left':83,
  1145. 'KP_Next':89,
  1146. 'KP_Page_Up':81,
  1147. 'KP_Right':85,
  1148. 'KP_Up':80,
  1149. 'ł':25,
  1150. 'l':46,
  1151. 'L':46,
  1152. 'Left':113,
  1153. 'm':58,
  1154. 'M':58,
  1155. 'Menu':135,
  1156. 'n':57,
  1157. 'N':57,
  1158. 'Num_Lock':77,
  1159. 'o':32,
  1160. 'O':32,
  1161. 'ø':32,
  1162. 'ö':47,
  1163. 'Ö':47,
  1164. 'p':33,
  1165. 'P':33,
  1166. 'Page_Down':117,
  1167. 'Page_Up':112,
  1168. 'Pause':127,
  1169. 'q':24,
  1170. 'Q':24,
  1171. 'r':27,
  1172. 'R':27,
  1173. 'Return':36,
  1174. 'Right':114,
  1175. 's':39,
  1176. 'S':39,
  1177. 'Scroll_Lock':78,
  1178. 'Shift_L':50,
  1179. 'Shift_R':62,
  1180. 'space':65,
  1181. 'ß':20,
  1182. 'Super_R':134,
  1183. 't':28,
  1184. 'T':28,
  1185. 'ŧ':28,
  1186. 'Tab':23,
  1187. 'u':30,
  1188. 'U':30,
  1189. 'ü':34,
  1190. 'Ü':34,
  1191. 'Up':111,
  1192. 'v':55,
  1193. 'V':55,
  1194. 'w':25,
  1195. 'W':25,
  1196. 'x':53,
  1197. 'X':53,
  1198. 'y':52,
  1199. 'Y':52,
  1200. 'z':29,
  1201. 'Z':29,
  1202. 'þ':33,
  1203. }
  1204. if __name__ == "__main__":
  1205. Application = OCRScreenReader()