ocrdesktop 41 KB

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