diff --git a/.github/workflows/python-lint-test.yml b/.github/workflows/python-lint-test.yml new file mode 100644 index 0000000..2844b42 --- /dev/null +++ b/.github/workflows/python-lint-test.yml @@ -0,0 +1,37 @@ +name: Python 🐛 Lint/Test + +on: + push: + pull_request: + +jobs: + test: + runs-on: windows-latest + strategy: + fail-fast: false + matrix: + python-version: ["3.10"] + steps: + - uses: actions/checkout@v3 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v3 + with: + python-version: ${{ matrix.python-version }} + - name: Install test dependencies + run: | + python -m pip install --upgrade pip + #we can't install this becuase it depends on natlink, which currently cannot be installed via pip. + #python -m pip install -e .[test] + #for now, just install dependencies required for linting sepcifically + python -m pip install flake8 + - name: Linting with flake8 + run: | + #stop the build if there are Python syntax errors or undefined names + flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics + #exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide + flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics + - name: Running pytest tests + run: | + echo "tests not implemented" + # pip install -e .[test] + # pytest diff --git a/.github/workflows/python-publish.yml b/.github/workflows/python-publish.yml new file mode 100644 index 0000000..9110a34 --- /dev/null +++ b/.github/workflows/python-publish.yml @@ -0,0 +1,25 @@ +name: Publish Package 📦 to PyPI +on: + release: + types: [published] # with prerelease and release + +permissions: + contents: read + id-token: write # IMPORTANT: this permission is mandatory for trusted publishing +jobs: + build_and_publish: + # Set up the environment `CI` references the secret `PYPI_API_TOKEN` in repository settings + # https://docs.github.com/en/actions/deployment/targeting-different-environments/using-environments-for-deployment#referencing-an-environment + environment: CI + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Installing build Dependencies + run: | + python -m pip install --upgrade pip + pip install build + - name: Build package + run: python -m build + - name: Publish package + uses: pypa/gh-action-pypi-publish@release/v1 + diff --git a/.gitignore b/.gitignore index 8bdec23..811a9fe 100644 --- a/.gitignore +++ b/.gitignore @@ -5,8 +5,12 @@ __pycache__/ /unimacro_test/testresult.txt /_number extended.py /_repeat.py +.vscode .vscode/launch.json /dist /configurenatlink_error.txt /README.html /website unimacro/html/ +/src/unimacro/UnimacroGrammars/rememberdialog.py +/tests/rememberdialog.py +/src/unimacro/UnimacroGrammars/rememberdialog.py diff --git "a/Packaging Python Projects \342\200\224 Python Packaging User Guide.url" "b/Packaging Python Projects \342\200\224 Python Packaging User Guide.url" deleted file mode 100644 index 24a0d52..0000000 --- "a/Packaging Python Projects \342\200\224 Python Packaging User Guide.url" +++ /dev/null @@ -1,2 +0,0 @@ -[InternetShortcut] -URL=https://packaging.python.org/tutorials/packaging-projects/ diff --git a/README.md b/README.md index 3409387..4b48ed4 100644 --- a/README.md +++ b/README.md @@ -7,47 +7,45 @@ Read more at [Natlink, including Unimacro and Vocolaa](https://qh.antenna.nl/uni Unimacro is reasonably stable, but still in alpha. Check the [Unimacro Issues](https://github.com/dictation-toolbox/unimacro/issues) to see the problem areas - probably nothing you can't live without. - - -## Install a prerelease of [Python for Win 32](https://github.com/mhammond/pywin32) -The latest the version of [Python for Win 32](https://github.com/mhammond/pywin32) in the Python Packing Index (300) has some bugs that affect Unimacro. -So you need to install a later version. - -You can download can updated pywin32 from https://github.com/mhammond/pywin32/pull/1622/checks, click on Artifacts, download the artifacts, extract the files to your computer somehwhere. - -In a shell with administrator privileges, -`pip install --force-reinstall .\pywin32-300.1-cp38-cp38-win32.whl`. +A limited number of grammars are by default available when you install unimacro: + + _control.py + _general.py + _folders.py + _lines.py + _brackets.py + _tags.py + _tasks.py + _clickbyvoice.py + _number simple.py ## Install unimacro -Install from the [Test Python Package Index](https://test.pypi.org/) +Install from the [Python Package Index](https://pypi.org/) with the following. -`pip install --no-cache --index-url https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple unimacro` +`pip install unimacro` + +But... when you install Natlink via the natlink installer, and proceed with "Configure Natlink via GUI" or "Configure Natlink via CLI", and choose to activate Unimacro, this "pip" action is automatically performed. + # Location of Grammars -Grammars installed with Unimacro will be installed in: +The Grammars listed above are installed with Unimacro in: the Lib\site-packages\unimacro\UnimacroGrammars sub-directory of your -Python installation. Good ones to start with include _folders.py and _clickbyvoice.py -as most users will find web and file system navigation by voice useful. +Python installation. More about [Unimacro Grammars](https://qh.antenna.nl/unimacro/grammars/globalgrammars/folders/index.html) # Developer instructions. -Follow the instructions for [Natlink](https://test.pypi.org/project/natlinkpy/), replacing 'natlink' with 'unimacro'. -The same commands for building packages and publishing are available in the unimacro root. - -If you wish to build or publish a package, there are: - -- build_package.ps1 and build_package.ps1 to build the packages. -- publish_package_pypi.ps1/.cmd to upload the package to the [Python Packaging Index](https://pypi.org/) -- publish_package_testpypi.ps1/.cmd to upload the packkage to the [Test Python Packaging Index](https://test.pypi.org/) +If you want to install your local unimacro development environment as the working unimacro: +`pip install -e .[dev,test] `. - +`py -m build` to build the Python package locally. +To publish a release to [Python Packaging Index](https://pypi.org/), [draft a new release](https://github.com/dictation-toolbox/unimacro/releases). diff --git "a/Why use Flit- \342\200\224 Flit 3.0.0 documentation.url" "b/Why use Flit- \342\200\224 Flit 3.0.0 documentation.url" deleted file mode 100644 index c73d11b..0000000 --- "a/Why use Flit- \342\200\224 Flit 3.0.0 documentation.url" +++ /dev/null @@ -1,2 +0,0 @@ -[InternetShortcut] -URL=https://flit.readthedocs.io/en/latest/rationale.html diff --git a/build_package.cmd b/build_package.cmd deleted file mode 100644 index 43e7a1c..0000000 --- a/build_package.cmd +++ /dev/null @@ -1 +0,0 @@ -flit build --format sdist --no-setup-py \ No newline at end of file diff --git a/build_package.ps1 b/build_package.ps1 deleted file mode 100644 index 6e0248d..0000000 --- a/build_package.ps1 +++ /dev/null @@ -1,4 +0,0 @@ -#build an sdist (source distribution) package for unimacro -#no wheel is built, one less thing to worry about -#use the no-setup option, which requires a -flit build --format sdist --no-setup-py \ No newline at end of file diff --git a/building_and_publishing_packages.txt b/building_and_publishing_packages.txt deleted file mode 100644 index 7a8bb50..0000000 --- a/building_and_publishing_packages.txt +++ /dev/null @@ -1,64 +0,0 @@ - - -Packages are build without a setup.py, and source only, as any PIP recent enough will be PEP517 compliant. -Flit is the simplest packaging tool that will work. Read about it here https://flit.readthedocs.io/en/latest/cmdline.html. - -Getting Ready to Publish a Package. -9 -Get your credentials for pypi and testpypi and add them to your ~\.pypirc. ~\.pypirc -seems very finicky even though it looks like a text file. If publishing to pypi or testpypi is -new it is suggested you copy pypirc_template to ~/.pypirc and add your token from your accounts for PyPi/TestPyPi. -(see in the natlink repository for this template) - -Customizing the Package for PyPi: - -Read https://flit.readthedocs.io/en/latest/pyproject_toml.html to see how to customize the description on PyPi, -licensing, etc. - -To build a package: - -Ensure you have flit ("pip install flit") - -Update the version number of the package. Make the number bigger in src/unimacro/__init__.py than it was the last time -a package was uploaded to TestPypi or PyPi. Flit uses that number as the release number on pypi. - -Start a power shell in the root of your git clone. if you are used to command shell, type "powershell" and that -will launch a windows powershell. - -enter the command "build-package". That should work. if you have untraccked git files you need to -address them by addding to .gitignore or adding to git. - - -To test a package. - -If that works, and you want to see if it works, i suggest uploading to testpypi. -use the powershell command: - -publish_package_testpypi - -if it publishes, then you will see the updated version number in natlink on testpypi https://test.pypi.org/search/?q=natlink - -Now install it using pip with this: - -pip --no-cache install --index-url https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple unimacro - -Remove any local projects for natlink from any Python Path variables, so that the version in site-packages gets loaded by -natlink. You can rename your dictation-toolbox root temporarily below which natlink lies, or your can temporarily rename -natlink to something like dev_natlink. - - - -To Publish a Package on PyPi after testing. - -You can't undo publishing a package on PyPi, so get it working on TestPyPi first. - -Then publish to testpypi using publish_package_pypy in powershell. - - - - - - - - - diff --git a/hallo.wav b/hallo.wav deleted file mode 100644 index 9978cd8..0000000 Binary files a/hallo.wav and /dev/null differ diff --git a/packaging instructions.txt b/packaging instructions.txt deleted file mode 100644 index 8d4bfdf..0000000 --- a/packaging instructions.txt +++ /dev/null @@ -1,2 +0,0 @@ -To create the package for upload to PyPy etc, -run the powershell script build_package.ps1 diff --git a/publish_package_pypi.cmd b/publish_package_pypi.cmd deleted file mode 100644 index d06db5d..0000000 --- a/publish_package_pypi.cmd +++ /dev/null @@ -1 +0,0 @@ -flit publish --format sdist --no-setup-py --repository pypi \ No newline at end of file diff --git a/publish_package_pypi.ps1 b/publish_package_pypi.ps1 deleted file mode 100644 index 7add4b3..0000000 --- a/publish_package_pypi.ps1 +++ /dev/null @@ -1,4 +0,0 @@ -#build an sdist (source distribution) package for unimacro -#no wheel is built, one less thing to worry about -#use the no-setup option, which requires a -flit publish --format sdist --no-setup-py --repository pypi \ No newline at end of file diff --git a/publish_package_tesetpypi.cmd b/publish_package_tesetpypi.cmd deleted file mode 100644 index b99fc8c..0000000 --- a/publish_package_tesetpypi.cmd +++ /dev/null @@ -1 +0,0 @@ -flit publish --format sdist --no-setup-py --repository testpypi \ No newline at end of file diff --git a/publish_package_testpypi.ps1 b/publish_package_testpypi.ps1 deleted file mode 100644 index 0eed12e..0000000 --- a/publish_package_testpypi.ps1 +++ /dev/null @@ -1,4 +0,0 @@ -#build an sdist (source distribution) package for unimacro -#no wheel is built, one less thing to worry about -#use the no-setup option, which requires a -flit publish --format sdist --no-setup-py --repository testpypi \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml index 92bfd04..58e3978 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -2,26 +2,69 @@ requires = ["flit_core >=2,<4"] build-backend = "flit_core.buildapi" -[tool.flit.metadata] -module="unimacro" -author = "Quintijn Hoogenboom" -author-email = "q.hoogenboom@antenna.nl" -home-page = "https://qh.antenna.nl/unimacro/" -description-file = "README.md" +[project] +name = "unimacro" +authors = [{name = "Quintijn Hoogenboom (maintainer)", email = "q.hoogenboom@antenna.nl"}] +dynamic = ["version", "description"] +requires-python = ">=3.10" +readme = "README.md" -requires=["natlink", - "debugpy >= 1.2.0", - "pywin32 >= 300"] - - + +dependencies = ["dtactions >= 1.6.2", + "debugpy >= 1.2.0", + "pywin32 >= 304", + "natlinkcore >= 5.4.1", + "FreeSimpleGUI>=5.1.0"] + classifiers=[ "Development Status :: 4 - Beta", "Topic :: Multimedia :: Sound/Audio :: Speech", "Topic :: Scientific/Engineering :: Human Machine Interfaces", - ] + "Environment :: Win32 (MS Windows)", + "Intended Audience :: Developers", + "Operating System :: Microsoft :: Windows", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: Implementation :: CPython", + "Topic :: Multimedia :: Sound/Audio :: Speech", + "Topic :: Software Development :: Libraries :: Python Modules", + ] -requires-python = ">=3.8" -keywords="dragon,speech,dictation,dictation-toolobx,unimacro,natlink" +[project.optional-dependencies] +test = [ + "pytest >=7.1.2","flake8" +] +dev = [ + "pyenvutils","entry-point-inspector","build" +] +[project.entry-points."natlink.grammars"] +unimacro_builtins = "unimacro.UnimacroGrammars:locateme" + +[project.entry-points."dt.loggers"] + unimacro ="unimacro:logname" + control="unimacro:control_logger_name" + folders="unimacro:folders_logger_name" -[tool.flit.scripts] +[tool.pytest.ini_options] +minversion = "7.1.2" +addopts = "--capture=tee-sys " +# very important +#the pythonpath lets pytest load code in your source area +#in addition to that in site-packages etc. +#you may want to run your tests without install natlinkcore with flit or pip +pythonpath = [ +] +testpaths= [ + "tests", +] +python_files = [ + "unittest*.py", + "test_*.py", + ] + +[project.scripts] - \ No newline at end of file +[project.urls] +homepage = "https://qh.antenna.nl/unimacro/" +repository="https://github.com/dictation-toolbox/unimacro" +source="https://github.com/dictation-toolbox/unimacro" diff --git a/pyproject.toml.orig b/pyproject.toml.orig new file mode 100644 index 0000000..f282a2e --- /dev/null +++ b/pyproject.toml.orig @@ -0,0 +1,71 @@ +[build-system] +requires = ["flit_core >=2,<4"] +build-backend = "flit_core.buildapi" + +[project] +name = "unimacro" +authors = [{name = "Quintijn Hoogenboom (maintainer)", email = "q.hoogenboom@antenna.nl"}] +dynamic = ["version", "description"] +requires-python = ">=3.10" +readme = "README.md" + + +dependencies = ["dtactions >= 1.5.7", + "debugpy >= 1.2.0", + "pywin32 >= 304", + "natlinkcore >= 5.3.7", + "pysimplegui"] + +classifiers=[ "Development Status :: 4 - Beta", + "Topic :: Multimedia :: Sound/Audio :: Speech", + "Topic :: Scientific/Engineering :: Human Machine Interfaces", + "Environment :: Win32 (MS Windows)", + "Intended Audience :: Developers", + "Operating System :: Microsoft :: Windows", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: Implementation :: CPython", + "Topic :: Multimedia :: Sound/Audio :: Speech", + "Topic :: Software Development :: Libraries :: Python Modules", + ] + +[project.optional-dependencies] +test = [ + "pytest >=7.1.2","flake8" +] +dev = [ + "pyenvutils","entry-point-inspector","build" +] +[project.entry-points."natlink.grammars"] +unimacro_builtins = "unimacro.UnimacroGrammars:locateme" + +[project.entry-points."dt.loggers"] + unimacro ="unimacro:logname" + control="unimacro:control_logger_name" + folders="unimacro:folders_logger_name" + +[tool.pytest.ini_options] +minversion = "7.1.2" +addopts = "--capture=tee-sys " +# very important +#the pythonpath lets pytest load code in your source area +#in addition to that in site-packages etc. +#you may want to run your tests without install natlinkcore with flit or pip +pythonpath = [ +] +testpaths= [ + "tests", + "src/unimacro/unimacro_test" +] +python_files = [ + "unittest*.py", + "test_*.py", + ] + +[project.scripts] + +[project.urls] +homepage = "https://qh.antenna.nl/unimacro/" +repository="https://github.com/dictation-toolbox/unimacro" +source="https://github.com/dictation-toolbox/unimacro" diff --git a/src/unimacro/actionclasses/__init__.py b/src/test_clipboardfiles/testempty.txt similarity index 100% rename from src/unimacro/actionclasses/__init__.py rename to src/test_clipboardfiles/testempty.txt diff --git a/src/unimacro/BrowseGrammar.py b/src/unimacro/BrowseGrammar.py index 90aa8ce..1336aa7 100644 --- a/src/unimacro/BrowseGrammar.py +++ b/src/unimacro/BrowseGrammar.py @@ -46,8 +46,8 @@ import copy import re import types -import natlinkutils -import gramparser # for splitApartLines +from natlinkcore import natlinkutils +from natlinkcore import gramparser # for splitApartLines ListCode = 0 # List SeqCode = 1 # sequence diff --git a/src/unimacro/BrowseGrammarApp.py b/src/unimacro/BrowseGrammarApp.py index fdedade..9983ca4 100644 --- a/src/unimacro/BrowseGrammarApp.py +++ b/src/unimacro/BrowseGrammarApp.py @@ -22,6 +22,8 @@ # # June 2020: adapt for python3, Quintijn Hoogenboom # Author: Bart Jan van Os, Version: 1.0 +#pylint:disable = C0209, W0622, C0321, W0612, W0702 +#pylint:disable = E1101 """This file implements a dialog/window to browse and train NatLink grammars @@ -51,19 +53,21 @@ from pywin.framework import dlgappcore import natlink -from natlinkutils import * +from natlinkcore.natlinkutils import * +from natlinkcore import natlinkstatus from natlinkutilsbj import SetMic,GrammarFileName -from operator import methodcaller -# hopelijk: QH -from natlinkutilsqh import getUnimacroDirectory -baseDirectory = getUnimacroDirectory() -print('baseDirectory: %s'% baseDirectory) from BrowseGrammar import * from listdialogs import ListDialog import TrainDialog import D_train +status = natlinkstatus.NatlinkStatus() +dataDirectory = status.getUnimacroDataDirectory() + +# seems to have gone from comctrl: +LVCFMT_LEFT = 0 + class GramHierList(hierlist.HierList): def __init__(self, root,Start, listBoxID = win32ui.IDC_LIST1): @@ -108,8 +112,8 @@ def OpenRule(self,RulePath): self.OpenNext(self.root,0,RulePath) def OpenStart(self): - if len(self.Start)==2: - Rule,Path,objPath=self.root.FindRulePath(self.Start) + if len(self.Start) == 2: + _Rule, _Path, objPath=self.root.FindRulePath(self.Start) for o in objPath: if not IsText(o): self.OpenRule(objPath) @@ -118,8 +122,7 @@ def GetHandleOf(self,item): HandlesFor=InverseDict(self.itemHandleMap) if item in HandlesFor: return HandlesFor[item] - else: - return None + return None IDC_EDIT=1000 @@ -154,7 +157,7 @@ def _maketemplate(self,title): win32con.WS_CHILD | win32con.WS_BORDER | win32con.WS_VISIBLE | win32con.WS_TABSTOP | commctrl.LVS_ALIGNLEFT | - commctrl.LVS_REPORT | LVS_EDITLABELS + commctrl.LVS_REPORT | commctrl.LVS_EDITLABELS ) t = [ [title, (0, 0, 500, 300), style, None, (8, "MS Sans Serif")], ["SysTreeView32", None, win32ui.IDC_LIST1, (0, 0, 1, 1), cs], @@ -205,7 +208,7 @@ def OnSyntaxClick(self, id, code): return 1 def OnOK(self): - if (self.LastFocused==IDC_SYNTAX): + if self.LastFocused==IDC_SYNTAX: self.ExpandSyntaxItem(self.SyntaxItem) def GotFocus(self,std, extra): @@ -219,7 +222,7 @@ def on_size (self, params): self.LayoutControls(w, h) def LayoutControls(self, w, h): - d=w/4 + d=int(w/4) self.Tree.MoveWindow((0,0,d,h)) self.Syntax.MoveWindow((d,0,w,h)) @@ -311,9 +314,10 @@ def FillList(self): numCols = len(self.colHeadings) index = 0 for col in self.colHeadings: - itemDetails = (commctrl.LVCFMT_LEFT, width*colw[index], col, 0) - self.Syntax.In - sertColumn(index, itemDetails) + ## change second variable to int, QH, 23092022:: + itemDetails = (LVCFMT_LEFT, int(width*colw[index]), col, 0) + print(f'index: {index}, itemDetails: {itemDetails}') + self.Syntax.InsertColumn(index, itemDetails) index = index + 1 index = 0 @@ -456,7 +460,7 @@ def InsertItems(self): self.SelItems=[0] def OnOK(self): - if (self.LastFocused==IDC_SYNTAX): + if self.LastFocused==IDC_SYNTAX: if len(self.SelItems)==1: self.ExpandSyntaxItem(self.SelItems[0]) @@ -490,6 +494,7 @@ def onTrain(self,nID,code): self.goTrain(ToTrain) def onTrainSpecial(self,nID,code): + #pylint:disable=W0101 return ## just disable... Names=[] Keys=list(D_train.SpecialTraining.keys()) @@ -511,9 +516,9 @@ def onNew(self,nID,code): pass def onEdit(self,nID,code): - pass + #pylint:disable=W0101 return - if (self.LastFocused==IDC_SYNTAX): + if self.LastFocused==IDC_SYNTAX: if len(self.SelItems)==1: print(self.SelItems[0]) self.EditControl=self.Syntax.EditLabel(0) @@ -546,8 +551,7 @@ def InitInstance(self): win32ui.Enable3dControls() self.dlg = self.frame = self.CreateDialog() if self.frame is None: - raise error("No dialog was created by CreateDialog()") - return + raise Exception("No dialog was created by CreateDialog()") self.PreDoModal() self.dlg.PreDoModal() self.dlg.DoModal() @@ -568,15 +572,15 @@ def CreateBrowseDialog(): try: GrammarFile=open(GrammarFileName,'rb') except: - GrammarFile=open(baseDirectory+'\\TestGrammar.bin','rb') + GrammarFile=open(dataDirectory+'\\TestGrammar.bin','rb') (Grammars,Start,All,Exclusive)=pickle.load(GrammarFile) GrammarFile.close() Grammars.Sort() if Exclusive: Name='Exclusive Grammars (Active Rules)' elif All: Name='All Grammars' else: Name='Active Grammars' - # dlg=GrammarDialog(Name,GramHierList(Grammars,Start)) - dlg=TrainGrammarDialog(Name,GramHierList(Grammars,Start)) + dlg=GrammarDialog(Name,GramHierList(Grammars,Start)) + # dlg=TrainGrammarDialog(Name,GramHierList(Grammars,Start)) return dlg @@ -595,8 +599,12 @@ def CheckCreateApp(): if __name__=='__main__': - pass - demodlg() - #demomodeless() + ## assume there is a "grammar.bin" in the UnimacroDataDirectory + CheckCreateApp() + # + # + # demodlg() + # #demomodeless() else: - CheckCreateApp() \ No newline at end of file + CheckCreateApp() + \ No newline at end of file diff --git a/src/unimacro/DialogServer.py b/src/unimacro/DialogServer.py index 17b2ba0..98aef1a 100644 --- a/src/unimacro/DialogServer.py +++ b/src/unimacro/DialogServer.py @@ -16,17 +16,18 @@ from pywin.framework import dlgappcore import natlink -from natlinkutils import * +from natlinkcore.natlinkutils import * +from natlinkcore import natlinkstatus from natlinkutilsbj import SetMic import listdialogs import D_ - +status = natlinkstatus.NatlinkStatus() RequestFileName=listdialogs.RequestFileName ResultFileName=listdialogs.ResultFileName # hopelijk: QH -from natlinkutilsqh import getUnimacroDirectory -baseDirectory = getUnimacroDirectory() + +dataDirectory = status.getUnimacroDataDirectory() IDC_EDIT=1000 @@ -110,7 +111,8 @@ def gotResults_Spelling(self,words,fullResults): chars=chars+'\\' else: chars=chars+c - natut.playString(chars) + + sendkeys(chars) if self.dlg: self.dlg.setCurrentAtTop() @@ -205,7 +207,7 @@ def GetRequestData(): try: RequestFile=open(RequestFileName,'r') except: - RequestFile=open(baseDirectory+'\\TestRequest.bin','r') + RequestFile=open(dataDirectory+'\\TestRequest.bin','r') Data=pickle.load(RequestFile) GrammarFile.close() return Data diff --git a/src/unimacro/DisabledGrammars/README.txt b/src/unimacro/DisabledGrammars/README.txt deleted file mode 100644 index e80f33f..0000000 --- a/src/unimacro/DisabledGrammars/README.txt +++ /dev/null @@ -1,11 +0,0 @@ -The python files in this folder are grammar files, but not active at this moment. - -The usable and - as much as possible - maintained grammars are in UnimacroGrammars. See for activating them the instructions there. - -Sample grammars (like _first_sample_docstring.py and natspeak_sample_docstring.py are also in this directory, and test things from the past are in this directory. - - - - - - diff --git a/src/unimacro/DisabledGrammars/_editcomments.py b/src/unimacro/DisabledGrammars/_editcomments.py deleted file mode 100644 index 8aa2feb..0000000 --- a/src/unimacro/DisabledGrammars/_editcomments.py +++ /dev/null @@ -1,812 +0,0 @@ -__version__ = "$Rev: 606 $ on $Date: 2019-04-23 14:30:57 +0200 (di, 23 apr 2019) $ by $Author: quintijn $" -# This file is part of a SourceForge project called "unimacro" see -# http://unimacro.SourceForge.net and http://qh.antenna.nl/unimacro -# (c) copyright 2003 see http://qh.antenna.nl/unimacro/aboutunimacro.html -# or the file COPYRIGHT.txt in the natlink\natlink directory -# -# This module was written by: Quintijn Hoogenboom (QH softwaretraining & advies) -# (August 2002, extensively revised October 2003) -# adaptations for interaction with emacs/voicecode march 2007 -# adapatations for latex, Frank Olaf Sem-Jacobsen (2011) -# -"""copy text to DragonPad for editing with Select-and-Say - -With this grammar you can copy text from an arbitrary window into -DragonPad (or other Select-and-Say program), edit with full -Select-and-Say capabilities, and paste it back into the original place. - -An important part of this grammar is the possibility to "Edit Comment" -and, new feature, doc strings. With "Edit Comment" the prefixing spaces -and "#" are stripped from the text. With "Edit Ready" the things are -put in front again. - -As a side effect edited texts are logged into a file, for future use in -the vocabulary builder. - -""" -class EditError(Exception): pass - -import natlink -natqh = __import__('natlinkutilsqh') -natut = __import__('natlinkutils') -natbj = __import__('natlinkutilsbj') -import utilsqh -import win32gui -import time -import re -import os -from actions import doAction as action -from actions import doKeystroke as keystroke -import actions -import ctypes - - -normalset = ['edit', 'copy', 'log'] -editset = ['ready', 'copy', 'log', 'edit'] - -# window handle edit program: -nsHandle = 0 -sourceHandle = 0 - -# regular expressions for edit comment and edit docstring -PythonCommentLine = re.compile(' *# ') -EmptyLines = re.compile(' *$') -StartingSpaces = re.compile(r'( *)') -# obsolete: -winwordStartComment = re.compile(" *'") -winwordEmptyCommentLines = re.compile("^ *' *$", re.M) - - - -ancestor = natbj.IniGrammar -class EditGrammar(ancestor): - language = natqh.getLanguage() - name = 'edit' - gramSpec = """ - exported = log (all|that|messages); - exported = (copy|cut) (all|that|messages) to (NatSpeak|DragonPad); - exported = edit (all|that|comment|file|"doc string"|remark) [(('python'|'cc') 'code') | 'latex']; - exported = edit (ready|cancel); - """ - - def initialize(self): - self.load(self.gramSpec) - self.defineLogfiles() - self.activateSet(normalset) - self.switchOnOrOff() - self.comment = 0 - self.remark = 0 - self.startString = '' - self.emacsWait= 0 - self.emacsHndle = 0 - self.word_handle = 0 - - def defineLogfiles(self): - """folder for logging texts and folder for messages""" - - umFolder = natqh.getUnimacroUserDirectory() - self.messagesFolder = os.path.join(umFolder, 'log messages') - self.logFolder = os.path.join(umFolder, 'log %s'%self.language, natqh.getUser()) - - - def gotBegin(self,moduleInfo): - if self.checkForChanges: - self.checkInifile() - - def gotResultsInit(self,words,fullResults): - """This is a new docstring""" - self.fullText = ' '.join(words) - - def gotResults_edit(self,words,fullResults): - global sourceHandle - print('---------------------edit: %s'% words) - modInfo = natlink.getCurrentModule() - progInfo = natqh.getProgInfo() - if progInfo[0] == self.startProgram.lower() or \ - self.startProgram == 'DragonPad' and progInfo[1].find('dragonpad') == 0: - self.DisplayMessage('Do not use "%s" in %s'% (self.fullText, self.startProgram)) - return - sourceHandle = modInfo[2] - ## If "edit all" is said, first select whole document - # mark cursor if possible: - fileMode = self.hasCommon(words, "file") - if fileMode: - toProg = 'emacs' - self.changeFileToProg(sourceHandle, toProg) - return - natqh.clearClipboard() - action('<>') - t = natqh.getClipboard() - - if self.hasCommon(words, ['all']): - action('<>') - - self.progName = natqh.getProgName() - self.comment = self.hasCommon(words,['comment','doc string']) - self.remark = self.hasCommon(words,['remark']) # for excel, not well implemented - self.emacs = self.hasCommon(words, ['code']) - self.latex = self.hasCommon (words, ['latex']) - - if not self.remark: - natqh.clearClipboard() - action('<>') - inputText = natqh.getClipboard() - if inputText.endswith('\n') and not self.emacs: - self.endsWithNewline = 1 - inputText = inputText[:-1] - else: - self.endsWithNewline = 0 - - if self.comment: - print('self.comment: %s'% self.comment) - if self.comment in ['doc string']: - try: - exec("com2text = self."+self.progName+"Docstring2text") - except AttributeError: - self.DisplayMessage('command '+self.fullText+' not valid for program: %s'%self.progName) - self.comment = 0 - return - else: - try: - exec("com2text = self."+self.progName+"Com2text") - except AttributeError: - self.DisplayMessage('command '+self.fullText+' not valid for program: %s'%self.progName) - self.comment = 0 - return - - # goto the other program: - if self.emacs: - self.python = self.hasCommon(words, 'python') - self.cc = self.hasCommon(words, 'cc') - if self.python: - self.emacsFile = r'C:/emacspythoncode.py' - elif self.cc: - self.emacsFile = r'C:/emacsCCcode.c' - else: - raise EditError('%s: invalid program code in command: %s'% (self.name, words)) - print('wanting to start emacs') - self.targetProg = "emacs" - if self.startEditProgram(prog=self.targetProg): - print('found emacs, fill in with file: %s'% self.emacsFile) - self.fillAndFindEmacsFile(inputText) - self.activateSet(editset) - else: - print('error with "edit that code command: %s"'% words) - return - elif self.latex: - - dll = ctypes.windll.shell32 - buf = ctypes.create_unicode_buffer(300) - dll.SHGetSpecialFolderPathW(None, buf, 0x0005, False) - print(buf.value) - - self.wordFile = buf.value + r'\wordlatextemp.tex' - print('wanting to start WinWord') - self.targetProg = "winword" - if self.startEditProgram(prog=self.targetProg): - print('found WinWord, fill in with file: %s'% self.wordFile) - self.fillAndFindWordFile(inputText) - self.activateSet(editset) - else: - print('error with "edit that code command: %s"'% words) - return - else: - self.targetProg = None - if self.startEditProgram(): - action('<>;') - else: - print('%s: problem with finding targetProg: %s'% (self.name, self.targetProg)) - return - if inputText: - natut.playString(inputText) - self.activateSet(editset) - - def gotResults_copy(self,words,fullResults): - global sourceHandle, nsHandle - modInfo = natlink.getCurrentModule() - if natut.matchWindow(modInfo, self.startProgram, self.startProgram): - self.DisplayMessage('Do not use "'+self.fullText+'" in '+self.startProgram) - return - # get Handle of this window: - sourceHandle = modInfo[2] - - ## If "edit all" is said, first select whole document - if (self.hasCommon(words, ['all'])): - action('<>') - natqh.Wait(0.2) - if (self.hasCommon(words, ['messages'])): - natqh.switchToWindowWithTitle('messages from python macros') - action('<>') - natqh.Wait(0.2) - # copy and goto NatSpeak - # clear clipboard, copy and goto DragonPad - natqh.saveClipboard() - if (self.hasCommon(words, ['copy'])): - action('<>') - elif (self.hasCommon(words, ['cut'])): - action('<>') - else: - print('no copy or cut in words: %s'% words) - return - natqh.rememberWindow() - if self.startEditProgram(): - if natqh.getClipboard(): - keystroke('{Ctrl+ExtEnd}{Enter}{Ctrl+v}') - natqh.returnToWindow(20,0.2, winHandle=sourceHandle) - natqh.restoreClipboard() - - def changeFileToProg(self,fromHndle, toProg): - """try getting file and folder in pythonwin and emacs""" - actions.putCursor() - action("<>") - fileName =actions.getPathOfOpenFile() - if fileName: - print('fileName: %s'% fileName) - else: - print('no filename found') - return - print("closing and return to: %s"% fileName) - action("<>") - if not self.startEditProgram(prog=toProg): - print('did not find emacs') - return - - action("<>") - action("W") - keystroke(fileName) - keystroke("{enter}") - actions.findCursor() - - # This is for the purpose of logging the text to a - # file, which can - # be used by the vocabulary builder later on. - def gotResults_log(self,words,fullResults): - natqh.saveClipboard() - if ( words[1] in ['all']): - #print "select all" - action('<>') - natqh.Wait(0.2) - - if (self.hasCommon(words, ['messages'])): - natqh.switchToWindowWithTitle('Messages') - natqh.Wait(0.5) - action('<>') - action('<>') - yearMonthDay = time.localtime(time.time())[:3] - messagesLogbase = 'Messages %s %s %s'% yearMonthDay - name = logToFileNow(self.messagesFolder, messagesLogbase, append=0) - if name: - natqh.Wait(1) - action("{alt+f4}") - self.DisplayMessage('Messages logged to %s'% name) - else: - self.DisplayMessage('error logging') - natqh.restoreClipboard() - return -## action("{alt+f4}") - # copy and goto NatSpeak - action('<>') - intros = dict(nld='teksten ', enx='texts ') - fileIntro = intros.get(self.language, 'texts ') - - yearMonth = time.localtime(time.time())[:2] - logFile = fileIntro + (" %s %s"%yearMonth) + '.txt' - name = logToFileNow(self.logFolder, logFile) - if name: - self.DisplayMessage('logged (append) to %s'% name) - else: - self.DisplayMessage('could not do logging') - - natqh.restoreClipboard() - - def gotResults_ready(self,words,fullResults): - modInfo = natlink.getCurrentModule() - checkHandle = modInfo[2] - if self.hasCommon(words,['cancel']): - if self.targetProg == 'emacs': - self.killEmacsFile() - - if checkHandle == nsHandle: - keystroke('{Ctrl+z}') - natqh.returnToWindow(20,0.2, winHandle=sourceHandle) - - else: # klaar: - if checkHandle != nsHandle and self.targetProg != 'winword' and self.targetProg != 'emacs': - self.DisplayMessage('command "%s" cannot be done from this window, only from "%s"'%(self.fullText, self.startProgram)) - else: - natqh.clearClipboard() - if self.targetProg == "emacs": - keystroke('{alt+x}mark-whole-buffer{enter}') - natqh.Wait() - keystroke('{alt+x}clipboard-kill-region{enter}') - natqh.Wait() - self.killEmacsFile() - else: - keystroke('{Ctrl+a}{Ctrl+c}') - if self.targetProg == "winword": - action ('<>') - natqh.Wait() - if natqh.waitForWindowTitle ('microsoft word') == 1: - progInfo = natqh.getProgInfo() - if progInfo[2] == 'child': - keystroke('{enter}') - natqh.Wait() - action ('<>') - t = natqh.getClipboard() - if self.automaticLogToFile: - intros = dict(nld='teksten auto ', enx='texts auto ') - fileIntro = intros.get(self.language, 'texts ') - yearMonth = time.localtime(time.time())[:2] - - logFile = fileIntro + (" %s %s"%yearMonth) + '.txt' - name = logToFileNow(self.logFolder, logFile) - ## natqh.killWindow() - natqh.returnToWindow(20,0.2, winHandle=sourceHandle) - if self.comment: - if self.comment in ['doc string']: - try: - exec("text2com = self."+self.progName+"Text2docstring") - except AttributeError: - self.DisplayMessage('command '+self.fullText+' for a comment is not valid for this program: %s'% self.progName) - self.comment = 0 - return None - else: - try: - exec("text2com = self."+self.progName+"Text2com") - except AttributeError: - self.DisplayMessage('command '+self.fullText+' for a comment is not valid for this program: %s'% self.progName) - self.comment = 0 - return None - - t = text2com(t) - keystroke(t) - elif self.remark: - # assume excel - action('{shift+f10}') - else: - # default action: - action('<>') - - if self.endsWithNewline: - keystroke('\n') - self.activateSet(normalset) - - def killEmacsFile(self): - """do the emacs commands to kill the file/buffer self.emacsPythonFile - - """ - self.emacsCommand('save-buffer') - self.emacsCommand('kill-this-buffer') - - def fillAndFindEmacsFile(self, text): - """get the file/buffer self.emacsPythonFile in the front - - """ - open(self.emacsFile, 'w').write(text) - - self.emacsCommand('find-file') - natqh.Wait() - keystroke('{backspace 100}') - natqh.Wait() - keystroke(self.emacsFile) - natqh.Wait() - keystroke('{enter}') - self.emacsCommand('delete-other-windows') - - def fillAndFindWordFile(self, text): - """get the file/buffer self.emacsPythonFile in the front - - """ - open(self.wordFile, 'w').write(text) - natqh.waitForWindowTitle ('Microsoft Word') - print("found Microsoft Word") - while 1: - action('<>') - if natqh.waitForWindowTitle ('Open') == 1: - print("got window title open") - progInfo = natqh.getProgInfo() - if progInfo[2] == 'child': - break - else: - print("not a child") - - print("open file") - natqh.Wait() - keystroke(self.wordFile) - natqh.Wait() - keystroke('{enter}') - natqh.Wait() - if natqh.waitForWindowTitle ('File conversion'): - keystroke('{alt+w}') - natqh.Wait() - keystroke ('{enter}') - keystroke('{ctrl+alt+n}') #Switch Word to draft mode - - - def emacsCommand(self, cmd): - """the alt+x commands, can be slowed down""" - keystroke('{alt+x}') - keystroke(cmd) - if self.emacsWait: - natqh.Wait(self.emacsWait) - keystroke('{enter}') - if self.emacsWait: - natqh.Wait(self.emacsWait) - - - - def startEditProgram(self, prog=None): - global nsHandle - prog = prog or "dragonpad" - hndle = actions.UnimacroBringUp(prog) - if not hndle: return # wrong - if prog == 'emacs': - self.emacsHndle = hndle - return hndle - elif prog == 'winword': - self.word_handle =hndle - return hndle - else: - nsHandle = hndle - return hndle -## -## natqh.rememberWindow() -## print ' starting: %s'% prog -## if prog == 'emacs': -## finish = 'emacs' -## -## if self.emacsHndle: -## try: -## natqh.SetForegroundWindow(self.emacsHndle) -## except: -## self.emacsHndle = None -## if not self.emacsHndle: -## natbj.AppSwapWith("emacs") -## elif prog: -## finish = prog -## natlink.recognitionMimic(["start", prog]) -## else: -## finish = None -#### natlink.recognitionMimic(["start", self.startProgram]) -## print 'waiting for new window...' -## try: -## natqh.waitForNewWindow(100,0.1) # 3 seconds to start or switch -## except natqh.NatlinkCommandTimeOut: -## self.DisplayMessage('cannot switch to edit program: "%s"'% (prog or self.startProgram)) -## nsHandle = 0 -## return 0 -## newMod = natlink.getCurrentModule() -## nsHandle = newMod[2] -## if finish: -## newProg = natqh.matchModule('emacs', modInfo=newMod) -## if finish == newProg: -## print 'emacs found ok' -## self.emacsHndle = newMod[2] -## action('SSK {alt+tab}') -## action('SSK {alt+tab}') -## else: -## print 'emacs NOT found' -## return 0 -## -## return 1 - - def fillInstanceVariables(self, ini=None): - """fills instance variables with data from inifile - - overload for grammar lines: get activate/deactivate windows - - """ -## print 'fillInstantVariables for %s'% self - ini = ini or self.ini - # If next variable is set to 1, after each "Edit Ready" command to - # complete text is written to a log file. - # - # You can always log the active selection or the whole window text - - self.automaticLogToFile = ini.getInt('general', 'automatic log to file') - # Set the directory you wish here. - ##startProgram = 'DragonPad' - self.startProgram = ini.get('general', 'start program', 'dragonpad') - # line length for automatic splitting - self.linelen = ini.getInt('general', 'line length') - - - - def fillDefaultInifile(self, ini=None): - """initialize as a starting example the ini file - - """ - ini = ini or self.ini - ancestor.fillDefaultInifile(self, ini) - self.ini.set('general', 'automatic log to file', '1') - self.ini.set('general', 'line length', '70') - self.ini.set('general', 'start program', 'DragonPad') - -################################################################ -# expressions for manipulating comment conversion functions: -# -# for Python these two functions: - -# This function converts a comment into text (stripped off the -# leading comment character) - def pythonwinCom2text(self, t): - # t is the input text, to be stripped from "#"s - # - # look for starting spaces and '#' and spaces: - m = PythonCommentLine.match(t) - if m: - self.prefix = m.group(0) - # get list of paragraphs, with generator function, - # regular expression for recognising comment lines given - L = [par for par in stripPrefix(t, self.prefix)] - return '\n'.join(L) - - elif not t: # starting with empty comment - natqh.saveClipboard() - action('<>{ctrl+c}') - t = natqh.getClipboard() - natqh.restoreClipboard() - p = len(t) - len(t.lstrip()) - self.prefix = ' '*p + "# " - if t.find(self.prefix) == 0: - return t[len(self.prefix):] - else: - return t - else: - raise utilsqh.QHerror('not a valid python comment, try again') - - -# - def pythonwinText2com(self, tIn): - """Format text back into chunks of python comment""" - # split into real paragraphs: - tList = tIn.split('\n') - tOut = [] - for t in tList: - if t: - lenSpaces = len(t) - len(t.lstrip()) - prefix = self.prefix + ' '*lenSpaces - localLineLen = self.linelen - len(prefix) - # format the string into parts that are less than maxLen - tOut.extend(utilsqh.splitLongString(t, maxLen=localLineLen, - prefix=prefix)) - else: - tOut.append(self.prefix.rstrip()) - - tOut = list(pythonwinList(tOut)) - if tOut: - return '\n'.join(tOut) - else: - return self.prefix.rstrip() - - - def pythonwinDocstring2text(self, t): - # t is the input text - m = StartingSpaces.match(t) - if m: - self.prefix = m.group(0) - # get list of paragraphs, with generator function, - # regular expression for recognising comment lines given - L = [par for par in stripPrefix(t, self.prefix)] - return '\n'.join(L) - - elif not t: # startin with current line - natqh.saveClipboard() - action('<>{ctrl+c}') - t = natqh.getClipboard() - natqh.restoreClipboard() - if not t: - self.prefix = '' - return '' - - p = len(t) - len(t.lstrip()) - self.prefix = ' '*p - if t.find(self.prefix) == 0: - return t[len(self.prefix):] - else: - return t - else: - self.prefix = '' - return t - - -# - def pythonwinText2docstring(self, tIn): - """Format text back into chunks of python - - - """ - # split into real paragraphs: and going on - tList = tIn.split('\n') - tOut = [] - - for t in tList: - if t: - lenSpaces = len(t) - len(t.lstrip()) - prefix = self.prefix + ' '*lenSpaces - localLineLen = self.linelen - len(prefix) - # format the string into parts that are less than maxLen - tOut.extend(utilsqh.splitLongString(t, maxLen=localLineLen, - prefix=prefix)) - else: - tOut.append(prefix.rstrip()) - - tOut = list(pythonwinList(tOut)) - if tOut: - return '\n'.join(tOut) - else: - return self.prefix - -def stripPrefix(Text, prefix): - """generator function, strips the given prefix - - if not there, yield an empty line, - with another line, raises error - - """ - L = Text.split('\n') - if not L: - yield '' - return - for t in L: - if not prefix: - yield t - elif t.find(prefix) == 0: - yield t[len(prefix):].rstrip() - elif t.find(prefix.rstrip()) == 0: - yield t[len(prefix.rstrip()):].rstrip() - elif EmptyLines.match(t): - yield '' - else: - raise EditError('stripPrefix: not a prefix: %s' % t) - -def pythonwinList(L): - """left strips lines that are indented by pythonwin - - assuming after # ldldsldsl the next line is indented, - after an empty line, the indenting is thrown away. - - Thus when pythonwin indents a line from itself, the string - must be stripped on the left side. - - """ - stripLeft = 0 - for l in L: - if stripLeft: - yield(l.lstrip()) - else: - yield l - # if we have a non empty line, the following must be stripped, - # because pythonwin indents the line by itself. - stripLeft = (l.strip() != '') - - -def logToFileNow(folderName, fileNameBase, append=1): - print('start log to file now: folderName: %s, fileNameBase: %s, append: %s'% \ - (folderName, fileNameBase, append)) - t = natqh.getClipboard() - if t: - utilsqh.createFolderIfNotExistent(folderName) - try: - if append: - base, ext = os.path.split(fileNameBase) - ext = ext or '.txt' - name = os.path.join(folderName, base+ext) -## print 'open for append: %s'% name - fout = open(name, 'a') - else: - name = findNewFile(folderName, fileNameBase) - if name: - fout = open(name, 'w') - else: - print('cannot find valid logfile') - return - - fout.write(t) - fout.write('\n\n') - fout.close() - return name - except IOError: - print('Grammar _editcomments: cannot log to file: %s:::%s'% (folderName, fileName)) - else: - print('nothing to log') - -def findNewFile(folderName, baseName,digits=2): - """find an unexisting file - - """ - base, ext = os.path.splitext(baseName) - ext = ext or '.txt' - - maxNumber = 10**digits - formatString = '%%s - %%.%sd%%s'% digits -## print 'formatString: %s'% formatString - for i in range(1, maxNumber): - filePart = formatString % (base, i, ext) - fullName = os.path.join(folderName, filePart) - if not os.path.isfile(fullName): - return fullName - - - - - -# standard stuff Joel (adapted for possible empty gramSpec, QH, unimacro) -thisGrammar = EditGrammar() -if thisGrammar.gramSpec: - thisGrammar.initialize() -else: - thisGrammar = None - -def unload(): - global thisGrammar - if thisGrammar: - thisGrammar.unload() - thisGrammar = None - - - -# ###### Visual Basic script for syntax highlighting of latex in Word -#Sub AssociateStyle(pattern As String, style As String, colour As Long) -#'Associate Styles with headings and quotations -#'Ensure Tools/References/Microsoft VBscript Regular Expression 5.5 is on -# -#Dim regEx, Match -#'Dim Matches As MatchCollection -#Dim str As String -#Dim region As Range -# -#Set regEx = CreateObject("VBScript.RegExp") -#regEx.pattern = pattern ' Set pattern. -#regEx.Global = True -#regEx.MultiLine = True -# -#'obtain matched RegExp. -#Set Matches = regEx.Execute(ActiveDocument.Range.Text) -#'MsgBox (Len(ActiveDocument.Range.Text)) -#'MsgBox (Matches.Count) -#'loop through and replace style -#For Each Match In Matches -# Set region = ActiveDocument.Range(Match.FirstIndex, Match.FirstIndex + Len(Match.Value)) -# If colour > -1 Then -# ' MsgBox (Match.Value) -# ' MsgBox (Match.FirstIndex) -# ' MsgBox (Len(Match.Value)) -# region.Font.ColorIndex = colour -# Else -# region.style = _ -# ActiveDocument.Styles(style) -# End If -#Next -# -#End Sub -# -# -#Sub AutoOpen() -#' -#' AutoOpen Macro -#' Macro recorded 5/6/2009 by reagle -#' -#FileName = ActiveDocument.FullName -#Extension = Right(FileName, 3) -#If Extension = "tex" Then -# Selection.WholeStory -# Selection.Font.Name = "Georgia" -# Selection.Font.Size = 12 -# Selection.ParagraphFormat.LineSpacing = 16 -# Selection.style = "Body Text" -# 'Call ReplaceMarkup("\\emph\{(*)\}", "<<\1>>") -# Call AssociateStyle("[{}]", "Quote", wdGreen) -# Call AssociateStyle("\\.*?}", "Quote", wdDarkBlue) -# Call AssociateStyle("^\\title{", "Heading 1", -1) -# Call AssociateStyle("^\\chapter{", "Heading 1", -1) -# Call AssociateStyle("^\\section{", "Heading 1", -1) -# Call AssociateStyle("^\\subsection{", "Heading 2", -1) -# Call AssociateStyle("^\\subsubsection{", "Heading 3", -1) -# Call AssociateStyle("^\\begin{quotation}", "Quote", -1) -# Call AssociateStyle("\$.*?\$", "Quote", wdRed) -# Call AssociateStyle("[^\\]%.*?$", "Quote", wdGray25) -# -#End If -# -#End Sub diff --git a/src/unimacro/DisabledGrammars/_first_sample_docstring.py b/src/unimacro/DisabledGrammars/_first_sample_docstring.py deleted file mode 100644 index 837652a..0000000 --- a/src/unimacro/DisabledGrammars/_first_sample_docstring.py +++ /dev/null @@ -1,45 +0,0 @@ -# Python Macro Language for Dragon NaturallySpeaking -# (c) Copyright 1999 by Joel Gould -# Portions (c) Copyright 1999 by Dragon Systems, Inc. -# -# This is an adaptation of the _sample1.py of Joel Goulds original release -# to be found in natlink/SampleMacros -# -# _first_sample_docstring.py -# -# This is a sample macro file with a single command -# When some window/control which can "receive" text (keystrokes) is in focus, -# say "first sample docstring". -# It should recognize the command and type: -# Heard macro "start" (words: "first sample docstring"){enter} -# -# This file represents the simplest possible example of a NatLink macro, -# with definition in docstring format. -# See http://qh.antenna.nl/unimacro/features/grammarclasses/docstringgrammar/index.html -# (March 2010, Quintijn Hoogenboom) -# -import natlink -natut = __import__('natlinkutils') -natqh = __import__('natlinkutilsqh') -natbj = __import__('natlinkutilsbj') -from actions import doKeystroke as keystroke -from actions import doAction as action - -class ThisGrammar(natbj.DocstringGrammar): - """simple example of a NatLink grammar with the rule definition in docstring - """ - def initialize(self): - self.load(self.gramSpec) - self.activateAll() - - def rule_start(self, words): - "first sample docstring" - keystroke('Heard macro "start" (words "first sample docstring"){enter}') - -thisGrammar = ThisGrammar() -thisGrammar.initialize() - -def unload(): - global thisGrammar - if thisGrammar: thisGrammar.unload() - thisGrammar = None diff --git a/src/unimacro/DisabledGrammars/_modes.py b/src/unimacro/DisabledGrammars/_modes.py deleted file mode 100644 index 455b472..0000000 --- a/src/unimacro/DisabledGrammars/_modes.py +++ /dev/null @@ -1,372 +0,0 @@ -# (unimacro - natlink macro wrapper/extensions) -# (c) copyright 2003 Quintijn Hoogenboom (quintijn@users.sourceforge.net) -# Ben Staniford (ben_staniford@users.sourceforge.net) -# Bart Jan van Os (bjvo@users.sourceforge.net) -# -# This file is part of a SourceForge project called "unimacro" see -# http://unimacro.SourceForge.net). -# -# "unimacro" is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License, see: -# http://www.gnu.org/licenses/gpl.txt -# -# "unimacro" is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; See the GNU General Public License details. -# -# "unimacro" makes use of another SourceForge project "natlink", -# which has the following copyright notice: -# -# Python Macro Language for Dragon NaturallySpeaking -# (c) Copyright 1999 by Joel Gould -# Portions (c) Copyright 1999 by Dragon Systems, Inc. -# -# _modes.py -# written by: Quintijn Hoogenboom (QH softwaretraining & advies) -# August 2008 -# for LaTeX/Math problem Angela Wigmore -# -"""trying to catch different modes, password (as example, LaTeX, Math)... - - -""" - -import time -import os -import sys -import types -import re -import natlink - -natut = __import__('natlinkutils') -natqh = __import__('natlinkutilsqh') -natbj = __import__('natlinkutilsbj') - - -# lists number1to99 and number1to9 etc. are taken from function getNumberList in natlinkutilsbj - -##ancestor = natbj.TestGrammarBase -ancestor = natbj.IniGrammar -class ThisGrammar(ancestor): - - # rule modes is always on (if the grammar is on that is) - # of the other 3 exported rules only one can be on... - - normalRules = ["modes"] - passwordRules = ["modes", "password_mode"] - latexRules = ["modes", "latex_mode"] - mathRules = ["modes", "math_mode"] - modes = ['normal', 'password', 'latex', 'math'] - exclusiveModes = ['password', 'latex'] # never make 'normal' exclusive! - - language = natqh.getLanguage() - # take from natlinkutilsbj: - ICAlphabet = natbj.getICAlphabet(language=language) - iniIgnoreGrammarLists = ['letter'] - - gramSpec = """ -# initially only this rule is on: - exported = (normal|latex|math|password) mode (on|off); - -# the exclusive mode rules: - exported = [+]; - exported = [+]; - exported = [+]; - -# the non exported rules: -# password: - = | | number ; - = | | number ; - -# latex/math: - = | | | | | ; - = | | | | | ; - -# subrules: - = {letter}; - = (Cap) {letter}; - = Greek {greekletter}; - = {operator}; - = (begin|end) {beginenddirective}; - = number ; - -# insert the numbers grammar, first test with _number!: - = [(comma|point|dot) ]; -"""+natbj.numberGrammar[language] - - - def gotBegin(self, moduleInfo): - if self.checkForChanges: - self.setMode("normal") - - def initialize(self): - self.load(self.gramSpec) - # if switching on fillInstanceVariables also fill number1to9 and number1to99! - self.switchOnOrOff() - self.setList('letter', self.ICAlphabet) - - self.currentMode = 'normal' - self.numKeystrokes = 0 - self.setMode('normal', silent=1) - - def gotResultsInit(self,words,fullResults): - # initialise the variables you want to collect the numbers in: - self.resetData() - - def resetData(self): - """reset things""" - # the tricks for the number rule: - self.waitForNumber('number') - self.minus = '' - - - def gotResults_modes(self,words,fullResults): - """switch on of off modes""" - - # note hasCommon to check for translated words as well (French, Dutch or synonyms) - # Some more sophisticated things should be done here, for example - ##when you try to switch off a mode which is not on, what should you do? - ## - ##Also when switching on another mode, maybe the previous mode should be switched off in a more nice way. - if self.hasCommon(words, 'off'): - self.setMode('normal') - return - if not self.hasCommon(words, 'on'): - self.DisplayMessage(""% ' '.join(words)) - return - - for mode in self.modes: - if self.hasCommon(words, mode): - print('want mode %s (%s)'% (mode, words)) - self.setMode(mode) - return - - def gotResults_letter(self,words,fullResults): - self.flushNumber() - for w in words: - if w in self.ICAlphabet: - w = w.split('\\')[0][0] - else: - continue - self.keystroke(w) - - def gotResults_ucletter(self,words,fullResults): - self.flushNumber() - for w in words: - if w in self.ICAlphabet: - w = w.split('\\')[0][0] - else: - continue - - self.keystroke(w.upper()) - - def gotResults_greekletter(self,words,fullResults): - self.flushNumber() - for w in words: - result = self.getFromInifile(w, 'greekletter') - if ';' in result: - results = [t.strip() for t in result.split(";")] - if self.currentMode == 'normal': - result = results[0] - elif self.currentMode == 'latex' and len(results) > 1: - result = results[1] - elif self.currentMode == 'math' and len(results) > 2: - result = results[2] - else: - result = results[-1] - result = self.doFunc('greekletter%s'% self.currentMode.capitalize(), result) - - print("w: %s, greekletter: %s" % (w, result)) - self.keystroke(result) - - def gotResults_operator(self,words,fullResults): - """get the operator part, go through mode dependent function - - the function self.operatorModename (Latex, Math, Password) is - executed if it is defined, input the words (one by one) - output also a string which is printed. - - """ - self.flushNumber() - for w in words: - result = self.getFromInifile(w, 'operator') - result = self.doFunc('operator%s'% self.currentMode.capitalize(), result) - print("w: %s, results: %s" % (w, result)) - self.keystroke(result) - - def gotResults_beginenddirective(self,words,fullResults): - self.flushNumber() - for w in words: - self.keystroke(w) - - def gotResults_numberrule(self,words,fullResults): - """only flush the number here""" - self.flushNumber() - - def flushNumber(self): - """gives the output of a number if it was catching one - - setup the catch for the next number (waitForNumber call) - """ - self.collectNumber() # gets result in self.number... - if self.number: - if self.minus: - self.number = '-' + self.number - self.keystroke(self.number) - self.number = '' - self.waitForNumber('number') - - - def gotResults(self,words,fullResults): - # step 5, in got results collect the number: - self.flushNumber() - return - if self.through: - res = 'collected number: %s, through: %s'%(self.number, self.through) - self.keystroke(res+'\n') - elif self.number: - if self.minus: - self.number = '-' + self.number - self.outputNumber(self.number) - elif self.pair: - self.keystroke("{f6}{f6}") - num = self.pair*2 - 1 - self.keystroke("{tab %s}"% num) - self.keystroke("<>") - - - def outputNumber(self, number): - self.keystroke(number) - prog = natqh.getProgName() - if prog in ['iexplore']: - self.keystroke('{tab}{extdown}{extleft}') - elif prog in ['natspeak']: - self.keystroke('{enter}') - elif prog in ['excel']: - self.keystroke('{tab}') - - def setMode(self, mode, silent=None): - """setting the correct mode and display a message - - the variable currentMode is set, - the relevant rules are activated - if silent fals, also DisplayMessage in recognition window... - """ - print('--- currentmode: %s'% self.currentMode) - if mode == 'normal': - if self.currentMode != 'normal': - self.doFunc('end%sMode'% self.currentMode.capitalize()) - elif self.currentMode not in ['normal', mode]: - self.doFunc('end%sMode'% self.currentMode.capitalize()) - - self.currentMode = mode - self.doFunc('begin%sMode'% mode.capitalize()) - - rules = getattr(self, '%sRules'% mode, '') - if rules: - exclusive = mode in self.exclusiveModes - self.activateSet(rules, exclusive=exclusive) - message = ""% mode - else: - message = ""% mode - if silent: - print(message) - else: - self.DisplayMessage(message) - - # functions for different modes: - def beginLatexMode(self): - """action at beginning of this mode""" - self.numKeystrokes = 0 - self.keystroke("$ ") - def beginMathMode(self): - """action at beginning of this mode""" - self.numKeystrokes = 0 - self.keystroke("\n") - def beginPasswordMode(self): - """action at beginning of this mode""" - self.numKeystrokes = 0 - def beginNormalMode(self): - """action at beginning of this mode""" - self.numKeystrokes = 0 - - def endLatexMode(self): - """action at end of this mode""" - self.keystroke(" $") - def endMathMode(self): - """action at end of this mode""" - self.keystroke("\n") - def endPasswordMode(self): - """action at end of this mode""" - self.numKeystrokes = 0 - def endNormalMode(self): - """action at end of this mode""" - self.numKeystrokes = 0 - - def operatorLatex(self, text): - return " %s "% text - def operatorMath(self, text): - return "\n %s"% text - - # utility functions for this grammar: - def doFunc(self, funcName, *args): - """apply a function, if present - prints to Message window when not present - - """ - func = getattr(self, funcName, '') - if func: - print('mode: %s, func: %s'% (self.currentMode, funcName)) - if args: - return func(*args) - else: - func() - else: - if args: - print('mode: %s, func: %s not present'% (self.currentMode, funcName)) - return args[0] - else: - print('modes, function not present: %s'% funcName) - - - def keystroke(self, keys): - """do a playString and record the number of self.keystrokes so far - - The number of keystrokes are collected in self.numKeystrokes, - This variable can be reset at end of a mode, end of phrase etc. - - """ - if keys: - natut.playString(keys) - self.numKeystrokes += len(keys) - - def cancelMode(self): - """for example if the mic is switched off - - reset to normal mode - """ - if self.currentMode != 'normal': - self.setMode('normal') - - # other name: - resetExclusiveMode = cancelMode - - -# standard stuff Joel (adapted for possible empty gramSpec, QH, unimacro) -thisGrammar = ThisGrammar() -if thisGrammar.gramSpec: - thisGrammar.initialize() -else: - thisGrammar = None - -def unload(): - global thisGrammar - if thisGrammar: thisGrammar.unload() - thisGrammar = None - -def changeCallback(type,args): - # not active without special version of natlinkmain, - # call the cancelMode, to switch off exclusive mode when mic toggles: - if ((type == 'mic') and (args=='on')): - return # check WAS in natlinkmain... - if thisGrammar: - thisGrammar.cancelMode() diff --git a/src/unimacro/DisabledGrammars/_number extended.py b/src/unimacro/DisabledGrammars/_number extended.py deleted file mode 100644 index e9803d8..0000000 --- a/src/unimacro/DisabledGrammars/_number extended.py +++ /dev/null @@ -1,584 +0,0 @@ -# (unimacro - natlink macro wrapper/extensions) -# (c) copyright 2003 Quintijn Hoogenboom (quintijn@users.sourceforge.net) -# Ben Staniford (ben_staniford@users.sourceforge.net) -# Bart Jan van Os (bjvo@users.sourceforge.net) -# -# This file is part of a SourceForge project called "unimacro" see -# http://unimacro.SourceForge.net). -# -# "unimacro" is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License, see: -# http://www.gnu.org/licenses/gpl.txt -# -# "unimacro" is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; See the GNU General Public License details. -# -# "unimacro" makes use of another SourceForge project "natlink", -# which has the following copyright notice: -# -# Python Macro Language for Dragon NaturallySpeaking -# (c) Copyright 1999 by Joel Gould -# Portions (c) Copyright 1999 by Dragon Systems, Inc. -# -# _number.py -# written by: Quintijn Hoogenboom (QH softwaretraining & advies) -# August 2003 -# -"""smart and reliable number dictation - -the number part of the grammar was initially provided by Joel Gould in -his grammar "winspch.py it is changed a bit, but essentially all sorts of numbers can be -dictated with his grammar. - -For real use in other grammars, copy the things from his grammar into another grammar. See -for example "_lines.py" and "firefox browsing.py". -BUT: first try if the logic of _number simple.py is enough. If not, study this grammar. - -BTW when dictating numbers in excel (doing my bookkeeping), I use this grammar (or the "number simple") all the time! - -QH september 2013: rewriting of the functions, ruling out optional command words. The optional word "and" has been removed - (now say "three hundred twenty" instead of "three hundred and twenty") - -QH211203: English numbers require more work: thirty three can be recognised as "33" or -as "30", "3". - -QH050104: standardised things, and put functions in natlinkutilsbj, so that -other grammars can invoke the number grammar more easily. -""" -from actions import doKeystroke as keystroke -from actions import doAction as action -from actions import getMetaAction - -natut = __import__('natlinkutils') -natqh = __import__('natlinkutilsqh') -natbj = __import__('natlinkutilsbj') -import iban # special module for banknumber (European mainly I think) -import types - -# Note: lists number1to99 and number1to9 and n1-9 and n20-90 etc. are taken from function getNumberList in natlinkutilsbj - -ancestor = natbj.IniGrammar -class ThisGrammar(ancestor): - - language = natqh.getLanguage() - #Step 1, choose one of next three grammar rules: - # the rule comes from these grammar rules - try: - number_rules = natbj.numberGrammarTill999[language] - except KeyError: - print('take number grammar from "enx"') - number_rules = natbj.numberGrammarTill999['enx'] - - #number_rules = natbj.numberGrammarTill999999[language] # including thousands - #number_rules = natbj.numberGrammar[language] # including millions - name = "number extended" - # do not use "To" instead of "Through", because "To" sounds the same as "2" - gramSpec = [""" - exported = [] (number )+; - exported = number Through ; - exported = page [Through ]; - exported = filename last page; - exported = Pair And ; - = | Minus | | Minus ; - exported = number (|)+; - = {spacing}; -"""] - gramSpec.append(" exported = IBAN {n00-99} {bankheader} ;") - gramSpec.append(number_rules) - try: - integer999 = natbj.numberGrammarTill999[language] - except KeyError: - print('take number grammar from "enx"') - integer999 = natbj.numberGrammarTill999['enx'] - ## 345567;345567 - ## these are special rules for making numbers of specific length. - ## when they appear to be usefull, I will try to make them available in other languages - ## and other cases too: - - amsterdamZuidRule = """ exported = | | ; - = zesentachtig ; - = point (<__thousandslimited> | ); - = {n0-9}{n0-9} | {n10-99}; - = {n0-9}{n0-9}{n0-9} | <__hundredslimited> | {n0-9} ; -<__hundredslimited> = hundred | <__2to9before> hundred | hundred <__1to99after> ; -<__thousandslimited> = thousand | <__2to9before> thousand | thousand <__1to99after> | - <__2to9before> thousand <__1to9after>; - - = <__thousandslimited> | ; - = {n0-9}+ | {n0-9} {n0-9} ; -<__thousands> = duizend | (<__1to99>|<__hundreds>) duizend | duizend (<__1to99>|<__hundreds>) | - (<__1to99>|<__hundreds>) duizend (<__1to99>|<__hundreds>); -<__2to9before> = {n2-9}; -<__1to99after> = {n1-99}; -<__1to9after> = {n1-9}; - -""" - -##8600 8650 86 2008 - def gotResults___hundredslimited(self,words,fullResults): - """will return only three digits as _sofar - goes together with <__2to9before> and <__1to99after> - - """ - didBeforeRules = ['__2to9before'] - doInAfterRules = ['__1to99after', '__1to9after'] - - print('__hundredslimited, prevRule: %s, nextRule: %s, words: %s'% (self.prevRule, self.nextRule, words)) - lenw = len(words) - for i in range(lenw): - if i == 0 and self.prevRule in didBeforeRules: - pass - else: - self._hundreds = 100 - if self.nextRule in doInAfterRules and i == lenw - 1: - # leave the "adding" action to nextRule - pass - else: - self._sofar += str(self._hundreds) - self._hundreds = 0 - - def gotResults___thousandslimited(self,words,fullResults): - """will return only four digits as _sofar - - goes together with <__2to9before> and <__1to99after> and possibly <__1to9after> - - """ - didBeforeRules = ['__2to9before'] - doInAfterRules = ['__1to99after', '__1to9after'] - - # print '__hundredslimited, prevRule: %s, nextRule: %s, words: %s'% (self.prevRule, self.nextRule, words) - lenw = len(words) - for i in range(lenw): - if i == 0 and self.prevRule in didBeforeRules: - pass - else: - self._thousands = 1000 - if self.nextRule in doInAfterRules and i == lenw - 1: - # leave the "adding" action to nextRule - pass - else: - self._sofar += str(self._thousands) - self._thousands = 0 - - def gotResults___1to99after(self, words, fullResults): - """should be after __hundredslimited or __thousandslimited - - must be defined in doInAfterRules ofter the corresponding rule - """ - didBeforeRules = ['__hundredslimited', '__thousandslimited'] - - print('__1to99after, prevRule: %s, nextRule: %s, words: %s'% (self.prevRule, self.nextRule, words)) - if len(words) > 1: - raise ValueError("rule __1to99after, expect only one word, got %s: %s"% (len(words), words)) - numWords = self.getNumbersFromSpoken(words) - num = numWords[0] - if self.prevRule == '__hundredslimited': - self._hundreds += num - self._sofar += str(self._hundreds) - self._hundreds = 0 - elif self.prevRule == '__thousandslimited': - self._thousands += num - self._sofar += str(self._thousands) - self._thousands = 0 - else: - print('__1to99after, no valid rule, got: %s, expected one of: %s'% (self.prevRule, didBeforeRules)) - self._sofar += str(num) - print('_sofar: %s'% self._sofar) - - def gotResults___1to9after(self, words, fullResults): - """should be after __hundredslimited or __thousandslimited - - must be defined in doInAfterRules ofter the corresponding rule - - Identical with gotResults___1to99after - """ - didBeforeRules = ['__hundredslimited', '__thousandslimited'] - - print('__1to99after, prevRule: %s, nextRule: %s, words: %s'% (self.prevRule, self.nextRule, words)) - if len(words) > 1: - raise ValueError("rule __1to99after, expect only one word, got %s: %s"% (len(words), words)) - numWords = self.getNumbersFromSpoken(words) - num = numWords[0] - if self.prevRule == '__hundredslimited': - self._hundreds += num - self._sofar += str(self._hundreds) - self._hundreds = 0 - elif self.prevRule == '__thousandslimited': - self._thousands += num - self._sofar += str(self._thousands) - self._thousands = 0 - else: - print('__1to99after, no valid rule, got: %s, expected one of: %s'% (self.prevRule, didBeforeRules)) - self._sofar += str(num) - print('_sofar: %s'% self._sofar) - - - def gotResults___2to9before(self, words, fullResults): - """together with __hundredslimited or __thousandslimited - - expect one word only, and treat with respect to the next rule - should be defined in didBeforeRules of the corresponding rule - """ - # print '__2to9before, prevRule: %s, nextRule: %s, words: %s'% (self.prevRule, self.nextRule, words) - - if len(words) > 1: - raise ValueError("rule __2to9before, expect only one word, got %s: %s"% (len(words), words)) - numWords = self.getNumbersFromSpoken(words, asStr=1) - numStr = numWords[0] - num = int(numStr) - if self.nextRule == '__hundredslimited': - self._hundreds = num * 100 - if self.nextRule == '__thousandslimited': - self._thousands = num * 1000 - else: - print('__2to9before, nextRule is NOT __hundredslimited of __thousandslimited') - self._sofar += numStr - print('_sofar: %s'% self._sofar) - - -##8640 8600 - -#failed to get this working: -# exported = (Tuple|List|Argument) (Number | (Variable|String) | None)+; - def __init__(self): - """start the inifile and add to grammar if needed a special rule - """ - self.startInifile() - #print 'enableSearchCommands: %s'% self.enableSearchCommands - if self.specialAmsterdamZuid: - self.gramSpec.append(self.amsterdamZuidRule) - ancestor.__init__(self) - - - def gotBegin(self,moduleInfo): - if self.checkForChanges: - self.checkInifile() - self.progInfo = natqh.getProgInfo(moduleInfo) - - def initialize(self): - if not self.language: - print("no valid language in grammar "+__name__+" grammar not initialized") - return - self.load(self.gramSpec) - # if switching on fillInstanceVariables also fill numbers lists like {n1-9} or {number1to99} - self.switchOnOrOff() - - def gotResultsInit(self, words, fullResults): - # Step 2: - # initialise the variables you want to collect the numbers in: - # defining them here makes testing in gotResults easier - self.number = '' # for most rules - self.page = '' # for page rule - self.through = '' # only for testnumber2 and pagenumber - self.pair = '' # only for the pair rule... - self.minus = False - self.ibanHeader = None # for banknumber - self.ibanCheck = None # for banknumber - self.totalNumber = '' # for multiple parts (Amsterdam Zuid, spacingnumber) - - #self.listtupleargument = '' - #self.Items = [] # for listtupleargumenthallo - # this line can be used to get the correct fullResults to be used in testIniGrammar.py for - # for debugging the rules! - # print 'fullResults of number extended: %s'% fullResults - - - def fillInstanceVariables(self): - """fills the necessary instance variables - - in this grammar a special rule for Loes Wijers, Amsterdam Zuid. - """ - # search commands (for Arnoud): - self.specialAmsterdamZuid = self.ini.getBool('general', 'special amsterdam zuid') - self.filenamePagenumbersPrefix = self.ini.get('general', 'filename page numbers prefix') - self.filenamePagenumbersPostfix = self.ini.get('general', 'filename page numbers postfix') - self.lastPage, self.lastThroug = None, None # filename page numbers - - def gotResults_testnumber1(self, words, fullResults): - # step 3: setting the number to wait for - # because more numbers can be collected, the previous ones be collected first - # if you expect only one number, this function can be skipped (but it is safe to call): - self.collectNumber() - result = self.hasCommon(words, 'number') - if self.hasCommon(words, 'number'): - if self.number: - # flush previous number - self.number =self.doMinus('number', 'minus') # convert to int - self.outputNumber(self.number) - self.waitForNumber('number') - else: - raise ValueError('invalid user input in grammar %s: %s'%(__name__, words)) - - def gotResults_testnumber2(self, words, fullResults): - # step 4 also: if more numbers are expected, - # you have to collect the previous number before asking for the new - self.collectNumber() - # self.minus is not relevant here, as this rule is about integers only... - # can ask for 'number' or for 'through': - if self.hasCommon(words, 'number'): - self.waitForNumber('number') - elif self.hasCommon(words, 'through'): - self.waitForNumber('through') - else: - raise NumberError('invalid user input in grammar %s: %s'%(__name__, words)) - - def gotResults_spacingnumber(self, words, fullResults): - self.collectNumber() - self.totalNumber += self.number - self.waitForNumber('number') - - def gotResults_spacing(self, words, fullResults): - self.collectNumber() - self.totalNumber += self.number - self.waitForNumber('number') - for w in words: - spacingchar = self.getFromInifile(w, 'spacing') - self.totalNumber += spacingchar - - def gotResults_pagenumber(self, words, fullResults): - # step 4 also: if more numbers are expected, - # you have to collect the previous number before asking for the new - self.collectNumber() - # self.minus is not relevant here, as this rule is about integers only... - # can ask for 'number' or for 'through': - if self.hasCommon(words, 'page'): - self.waitForNumber('page') - elif self.hasCommon(words, 'through'): - self.waitForNumber('through') - else: - raise NumberError('invalid words in pagenumber rule in grammar %s: %s'%(__name__, words)) - - def gotResults_filenamelastpage(self, words, fullResults): - # additional command, compose filename with the last called page number(s). - # need variables in inifile section [general]: filename pagenumber prefix and filename pagenumber postfix - # if these are not set, of if no page numbers are "remembered", do nothing - if self.lastPage: - if self.lastThroug: - lp, lt = int(self.lastPage), int(self.lastThroug) - if lt > lp: - pagePart = '%s-%s'% (lp, lt) - else: - pagePart = self.lastPage - else: - pagePart = self.lastPage - else: - print('numbers extended: no page numbers command issued yet, skip command') - return - if not self.filenamePagenumbersPrefix: - print('%s: command "%s", please specify "filename page numbers prefix" in section [general] of inifile'% (' '.join(words), self.name)) - if not self.filenamePagenumbersPostfix: - print('%s: command "%s", please specify "filename page numbers postfix" in section [general] of inifile'% (' '.join(words), self.name)) - if self.filenamePagenumbersPrefix and self.filenamePagenumbersPostfix: - fName = self.filenamePagenumbersPrefix + pagePart + self.filenamePagenumbersPostfix - action("SCLIP %s"% fName) - - def gotResults_pair(self, words, fullResults): - # here a bit different logic for the place to collect the previous number. - # - self.pair = 'pair' - if self.hasCommon(words, 'and'): - self.collectNumber() - self.number = self.doMinus('number', 'minus') - self.waitForNumber('pair') - else: - self.waitForNumber('number') - - def gotResults_banknumber(self,words,fullResults): - """get first 8 characters from bank name (list), rest from numbers grammar - """ - self.ibanHeader = self.getFromInifile(words[-1], 'bankheader') - self.ibanCheck = "%.2d"% self.getNumberFromSpoken(words[-2]) - self.waitForNumber('number') - - def gotResults_number(self, words, fullResults): - # step: when in this rule, the word Minus (or synonym or translation) has been spoken.. - self.minus = True - - def gotResults_numberazone(self, words, fullResults): - """first part of the number""" - if not self.totalNumber: - self.totalNumber = '86' - # print 'totalNumber: ', self.totalNumber - self.collectNumber() - self.totalNumber += self.number - self.number = '' - # wait for a number of 6 digits, if not, do NOT output!! - self.waitForNumber('number', 6) - - def gotResults_numberaztwo(self, words, fullResults): - """second part of the number""" - self.collectNumber() - self.totalNumber += self.number - self.number = '' - self.totalNumber += '.' - # wait for a number of 6 digits, if not, do NOT output!! - self.waitForNumber('number', 4) - -# # # # = {n0-9}{n0-9} | {n10-99}; -# # # # = {n0-9}+ | <__hundreds> | {n0-9} ; - def gotResults_numbertwodigits(self, words, fullResults): - numWords = self.getNumbersFromSpoken(words, asStr=1) - numberString = ''.join(numWords) - self._sofar += numberString - - def gotResults_numberthreedigits(self, words, fullResults): - numWords = self.getNumbersFromSpoken(words, asStr=1) - numberString = ''.join(numWords) - self._sofar += numberString - - def gotResults_numberfourdigits(self, words, fullResults): - numWords = self.getNumbersFromSpoken(words, asStr=1) - numberString = ''.join(numWords) - self._sofar += numberString - - def gotResults_numbersixdigits(self, words, fullResults): - numWords = self.getNumbersFromSpoken(words, asStr=1) - numberString = ''.join(numWords) - self._sofar += numberString - - def gotResults(self, words, fullResults): - # step 5, in got results collect the number: - self.collectNumber() - - if self.totalNumber: - # multiple numbers, AmsterdamZuid - self.totalNumber += self.number - print('gotResults totalNumber: ', self.totalNumber) - if self.message: - print('Error collecting the number, do NOT output the number...') - print(self.message) - else: - self.outputNumber(self.totalNumber) - if len(self.totalNumber) == 13 and self.totalNumber[-5] == '.': - keystroke("{tab}") - elif len(self.totalNumber) == 5 and self.totalNumber[0] == '.': - keystroke("{tab}") - - return - - if self.page: - ## page numbers rule (for child windows, adobe [acrord32] of pdf24.) - self.lastPage, self.lastThroug = self.page, self.through - print('setting lastPage and lastThroug: %s, %s'% (self.lastPage, self.lastThroug)) - isTop = (self.progInfo[2] == 'top') - if isTop: - out = ' page %s'% self.page - else: - ma = getMetaAction('pagestart', progInfo=self.progInfo) - if not ma: - print('no metaactions defined for pagestart, stop command %s'% self.progInfo[0]) - return - action("<>") - keystroke(self.page) - if self.progInfo[0] == 'pdf24-creator' and self.through == '': - self.through = self.page - - if self.through: - if isTop: - out += '-%s'% self.through - else: - action("<>") - keystroke(self.through) - action("<>") - if isTop: - keystroke(out) - return # page command - - if self.through: - # only print in Messages window: - res = 'collected number: %s, through: %s'%(self.number, self.through) - #keystroke(res+'\n') - print(res+'\n') - - elif self.pair: - self.pair = self.doMinus('pair', 'minus') - print("(%s, %s) "% (self.number, self.pair)) - - - #elif self.listtupleargument: - # print 'self.listtupleargument in gotResults: %s'% self.listtupleargument - # if self.number: - # self.number = self.doMinus('number', 'minus') - # self.Items.append(self.number) - # - # if self.dictated: - # self.Items.append(''.join(self.dictated)) - # self.dictated = None - # - # result = repr(self.Items) - # print 'result: %s'% self.Items - # if self.listtupleargument == 'list': - # print 'list: %s'% result - # elif self.listtupleargument == 'tuple': - # result = repr(tuple(self.Items)) - # print 'tuple: %s'% result - # else: - # result = repr(tuple(self.Items)).replace(', ', ',') - # result = result.replace(', ',',') - # print 'argument: %s'% result - # - elif self.ibanCheck and self.ibanHeader: - try: - # print 'ibanheader: %s, number: %s'% (self.ibanHeader, self.number) - result = Iban = iban.create_iban(self.ibanHeader[:2], self.ibanHeader[2:], self.number) - except iban.IBANError as err: - print('invalid iban %s, %s (%s)'% (self.ibanHeader, self.number, err)) - return - if result[2:4] == str(self.ibanCheck): - keystroke(result) - else: - print('invalid check: %s (%s) '% (self.ibanCheck, result)) - - elif self.number: - # last part if all others failed: - self.number = self.doMinus('number', 'minus') - self.outputNumber(self.number) - - - def outputNumber(self, number): - if type(number) in [int, float]: - number = str(number) - - keystroke(number) - prog = natqh.getProgName() - if prog in ['iexplore', 'firefox', 'chrome', 'safari']: - keystroke('{tab}') - elif prog in ['natspeak']: - keystroke('{enter}') - elif prog in ['excel', 'winword', 'soffice']: - keystroke('{tab}') - - - - def doMinus(self, number, minus): - """return the minus version of number, is self.minus is set - - pass in the names of the number variable and the name of the minus variable. - return the wanted number. - """ - Nstring = getattr(self, number) - Nstring = Nstring.strip() - Minus = getattr(self, minus) - if not Nstring: - setattr(self, minus, False) - return '' - - if Minus: - if Nstring.startswith('-'): - Nstring = Nstring[1:] - else: - Nstring = '-'+Nstring - setattr(self, minus, False) - return Nstring - -# standard stuff Joel (adapted for possible empty gramSpec, QH, unimacro) -thisGrammar = ThisGrammar() -if thisGrammar.gramSpec: - thisGrammar.initialize() -else: - thisGrammar = None - -def unload(): - global thisGrammar - if thisGrammar: thisGrammar.unload() - thisGrammar = None \ No newline at end of file diff --git a/src/unimacro/DisabledGrammars/_setpriority.py b/src/unimacro/DisabledGrammars/_setpriority.py deleted file mode 100644 index c370cea..0000000 --- a/src/unimacro/DisabledGrammars/_setpriority.py +++ /dev/null @@ -1,53 +0,0 @@ -############################################################################ -# -# global Python grammar file: _setpriority.py -import win32con,win32api,win32process -# -# This file is loaded automatically when the Python subsystem starts because -# its filename begins with an underscore (the signal for a global module). -# -# Its only goal is to change the process priority of Natspeak to : -desiredPClass = win32process.HIGH_PRIORITY_CLASS # (define new priority here) -# upon start of the system, and display the change in the message window. -# -# If you don't want to see the change notification in case of succes, -# set the following constant to zero -displayResults = 0 -# -# This scripts appears to work for DNS4 and 5, under NT 4 and NT 2000. -# It is assumed that the macro system is run under the process control of NatSpeak, -# and the user has enough rights to change the priority of the process. -# -# Author: B.J. van Os - - -def GetPriorityClassName(pClass): - if pClass==win32process.HIGH_PRIORITY_CLASS: - return 'HIGH' - elif pClass==win32process.NORMAL_PRIORITY_CLASS: - return 'NORMAL' - elif pClass==win32process.IDLE_PRIORITY_CLASS: - return 'IDLE' - elif pClass==win32process.REALTIME_PRIORITY_CLASS: - return 'REAL' - elif pClass==win32process.ABOVE_NORMAL_PRIORITY_CLASS: - return 'ABOVE NORMAL' - elif pClass==win32process.BELOW_NORMAL_PRIORITY_CLASS: - return 'BELOW NORMAL' - - -id = win32api.GetCurrentProcessId() -h = win32api.OpenProcess(win32con.PROCESS_ALL_ACCESS,0,id) -oldPClass = win32process.GetPriorityClass(h) - -if displayResults: print('Current Process Priority = ',GetPriorityClassName(oldPClass)) - -if oldPClass == desiredPClass: - if displayResults: print('WARNING: Current Process already has desired priority!') -else: - win32process.SetPriorityClass(h,desiredPClass) - newPClass=win32process.GetPriorityClass(h) - if oldPClass==newPClass: - print('WARNING: Change of process priority failed!') - else: - if displayResults: print('New Process Priority = ',GetPriorityClassName(newPClass)) diff --git a/src/unimacro/DisabledGrammars/_shownumbersplus.py b/src/unimacro/DisabledGrammars/_shownumbersplus.py deleted file mode 100644 index 8ca5342..0000000 --- a/src/unimacro/DisabledGrammars/_shownumbersplus.py +++ /dev/null @@ -1,351 +0,0 @@ -__version__ = "$Rev: 398 $ on $Date: 2011-03-07 14:50:15 +0100 (ma, 07 mrt 2011) $ by $Author: quintijn $" -# This file is part of a SourceForge project called "unimacro" see -# http://unimacro.SourceForge.net and http://qh.antenna.nl/unimacro -# (c) copyright 2003 see http://qh.antenna.nl/unimacro/aboutunimacro.html -# or the file COPYRIGHT.txt in the natlink\natlink directory -# -# _shownumbersplus.py -# -# operate on shownumbersplus, from Max Roth -# written by Quintijn Hoogenboom (QH softwaretraining & advies), -# february 2011 -# -"""Do commands on the numbers shown by shownumbersplus -""" -# -# -import natlink -import win32event -import pywintypes -import win32api - -import monitorfunctions # for get_taskbar_position -import time -import os -import os.path -import sys -from actions import doAction as action -natut = __import__('natlinkutils') -natqh = __import__('natlinkutilsqh') -natbj = __import__('natlinkutilsbj') - -language = natqh.getLanguage() -# center mouse after taskswitch (not good with XP and choice boxes in taskbar) -# -ancestor=natbj.DocstringGrammar -class ThisGrammar(ancestor): - - language = natqh.getLanguage() - name = "show numbers plus" - prevHndle = None - - if language == 'nld': - gramSpec = natbj.numberGrammarTill999['nld'] - else: - gramSpec = natbj.numberGrammarTill999['enx'] # with possible translations for other languages - - def initialize(self): - self.load(self.gramSpec) - self.prevHndle = None - self.SNPActive = None - self.switchOnOrOff() # initialises lists from inifile, and switches on - # if all goes well (and variable onOrOff == 1) - self.mode = None - self.prevTopHndle = None - - - def switchOn(self, **kw): - """SNP overload, switches grammar on, activates all reenles - - check first if SNP is active, if not, leave the off state - """ - if self.SNPIsRunning(onlyShow=1): - self.SNPActive = 1 # just for trying - ancestor.switchOn(self, **kw) - self.openMicMode() # giving the tray numbers - #print '%s switched on'% self.name - else: - self.SNPActive = 0 - print('Show Numbers Plus! is not running, grammar "%s" not activated'% self.name) - - def switchOff(self, skipCancelMode=None): - """SNP overload, switches grammar off, deactivates all rules - - """ - if self.SNPActive and not skipCancelMode: - self.cancelMode() - ancestor.switchOff(self) - - def cancelMode(self): - """switch off numbers and continuous mode - """ - if self.SNPActive and self.SNPIsRunning() and self.prevHndle: - if self.debug: - print('SNP cancelMode') - self.command('HIDENUMBERS') - self.command('HIDENUMBERSTASKBAR') - self.mode = '' - - def openMicMode(self): - """switch off numbers and continuous mode - """ - if self.SNPActive and self.prevHndle: - self.command('SHOWNUMBERSTASKBAR') - self.mode = '' - - def gotBegin(self, moduleInfo): - if self.checkForChanges: - self.checkInifile() # refills grammar lists and instance variables - if self.prevHndle == moduleInfo[2]: - return - - # if module changes, reset mode: - prog, title, topchild, hndle = natqh.getProgInfo(moduleInfo) - if topchild == 'child': - self.prevTopHndle = self.prevHndle - elif self.prevTopHndle != moduleInfo[2]: - # keep mode when switching from child to top again: - self.mode = '' - self.prevHndle = moduleInfo[2] - - def gotResultsInit(self, words, fullResults): - self.taskbar = self.inwindow = 0 - self.waitForNumber('inwindow') - self.clicktype = 1 - self.action = '' - - def fillInstanceVariables(self): - """fill eg taskbar posision - """ - self.centerMouse = self.ini.get('general', 'center mouse after action', '') - self.debug = self.ini.get('general', 'debug', '') - self.taskbarPosition = self.ini.get('general', 'taskbar position', 'bottom') - if self.debug: - print('shownumbersplus grammar, taskbar position: %s'% self.taskbarPosition) - - def rule_showhidenumbers(self, words): - """#commands for switching on or off the numbers - (show|hide) numbers [continuous]; - """ - show = self.hasCommon(words, 'show') - hide = self.hasCommon(words, 'hide') - continuous = self.hasCommon(words, 'continuous') - if self.debug: - print('continuous: %s'% continuous) - if show and hide: - raise ValueError('shownumbersplus, got both show and hide: %s'% words) - elif not (show or hide): - raise ValueError('shownumbersplus, got neither show nor hide: %s'% words) - if show: - cmd = 'SHOWNUMBERS' - if continuous: - self.mode = 'continue' - else: - cmd = 'HIDENUMBERS' - self.mode = '' - self.command(cmd) - - def rule_showhidetraynumbers(self, words): - """(show|hide) (tray) [numbers]; - """ - show = self.hasCommon(words, 'show') - hide = self.hasCommon(words, 'hide') - - if show and hide: - raise ValueError('shownumbersplus, got both show and hide: %s'% words) - elif not (show or hide): - raise ValueError('shownumbersplus, got neither show nor hide: %s'% words) - if show: - cmd = 'SHOWNUMBERSTASKBAR' - else: - cmd = 'HIDENUMBERSTASKBAR' - self.command(cmd) - - def rule_taskbar(self, words): - """(tray) {n1-40} [||] - """ - self.taskbar = self.getNumbersFromSpoken(words)[0] - self.clicktype = 1 - # actions in self.gotResults, with self.taskbar set - - def rule_inwindow(self, words): - """ [continue|stop|{afterclickactions}] - """ - if self.hasCommon(words[-1], 'continue'): - self.mode = 'continue' - elif self.hasCommon(words[-1], 'stop'): - self.mode = None - pass # never comes here, ends in gotResults with a number in self.inwindow - - - def subrule_click(self, words): - '{clicks}' - self.clicktype = self.getFromInifile(words, 'clicks') - - def subrule_action(self, words): - '{actions}' - self.action = self.getFromInifile(words, 'actions') - - def gotResults(self, words, fullResults): - """perform the resulting actions - """ - self.collectNumber() - if self.debug: - print('collected: %s'% self.inwindow) - # - if self.taskbar: - #asked for a taskbar number... - cmd = 'DOACTIONTRAY=(%s, %s)'% (self.taskbar, self.clicktype) - self.command(cmd) - # see if stacked tray shows up - className = natqh.getClassName() - #print 'className: %s'% className - if className == "TaskListThumbnailWnd": - if self.debug: - print('stacked taskbar, display numbers again') - cmd = 'SHOWNUMBERS' - self.command(cmd) - natqh.visibleWait() - self.mode = None - - if self.inwindow: - # intercept when you are in the stacked explorer (taskbar) windows: - className = natqh.getClassName() - #print 'classname: %s'% className - if className == "TaskListThumbnailWnd": - self.doAlternativeClick(className, self.inwindow) - else: - cmd = 'DOACTIONSHOWNUMBERS=(%s, %s)'% (self.inwindow, self.clicktype) - if self.debug: - print('inwindow cmd: %s'% cmd) - self.command(cmd) - if self.action: - action("VW") # visible wait - if self.debug: - print('shownumbers plus action: %s'% self.action) - action(self.action) - - if self.centerMouse: - if self.debug: - print('center mouse') - natqh.Wait() - natqh.doMouse(1, 5, 0.3, 0.3, 0, 0) # relative in client area, no clicking - # must check this: - if self.mode == 'continue': - hndle = natlink.getCurrentModule()[2] - if hndle != self.prevHndle: - self.mode = '' # new window - return - if self.debug: - print('continuous, show numbers again') - action("VW") - cmd = 'SHOWNUMBERS' - self.command(cmd) - - - def command(self, cmd): - """do a shownumbersplus command - - """ - if not self.SNPActive: - if self.debug: - print('SNP not running, call "switch on %s" to restar grammar, after you started SNP! again'% self.name) - return - - if self.inGotBegin or self.status == 'new': - print('SNP command not executed (initializing or gotbegin): %s'% cmd) - return - - - hndle = self.SNPIsRunning() - if hndle: - script = 'DdeExecute "ShowNumbersPlus", "CONTROL", "[%s]"'% cmd - if self.debug: - print('SNP: %s'% cmd) - try: - natlink.execScript(script) - except: - '''Ddeexecute failed for shownumbersplus command: "%s". - This is strange, because apparently Show Numbers Plus! is running. - Error message: %s, %s'''% (cmd, sys.exc_info()[0], sys.exc_info()[1]) - self.switchOff(skipCancelMode=1) - self.SNPActive = 0 - else: - self.closeMutex() - else: - print('''No DdeExecute to shownumbersplus: "%s". -Because SNP seems to be not running.'''% cmd) - self.switchOff() - - - - def doAlternativeClick(self, className, num): - """instead of click perform another (keystrokes) action - """ - - if className == "TaskListThumbnailWnd": - taskbarPosition = monitorfunctions.get_taskbar_position() # notices changes on the fly! - # which way to scroll through a stack of taskbar buttons: - initialKeys = dict(left='{down}', top='{right}', - right='{left}{down}', bottom='{right}') - scrollKeys = dict(left='down', top='right', - right='down', bottom='right') - try: - initial = initialKeys[taskbarPosition] - scrollKey = scrollKeys[taskbarPosition] - except KeyError: - print('key not found "taskbarPosition": %s'% taskbarPosition) - return - # go to first of popup windows (depending on taskbar location) - action(initial) - if num and num != '0': - action('{%s %s}'% (scrollKey, num)) - action('{enter}') - else: - print('should not call doAlternativeClick for className: %s'% className) - - def SNPIsRunning(self, onlyShow=None): - MutexName = "ShowNumbersPlusGMUTEX" - MUTEX_ALL_ACCESS = 0X1F0001 - try: - SingleAppHandle = win32event.OpenMutex(MUTEX_ALL_ACCESS, 0, MutexName) - except pywintypes.error as details: - if details[0] == 2: - self.MutexHndle = None - return - self.MutexHndle = SingleAppHandle - if onlyShow: - self.closeMutex() - return SingleAppHandle - - def closeMutex(self): - if self.MutexHndle: - win32event.ReleaseMutex(self.MutexHndle) - self.MutexHndle = None - - - -# standard stuff Joel (adapted for possible empty gramSpec, QH, unimacro) -thisGrammar = ThisGrammar() -if thisGrammar.gramSpec: - thisGrammar.initialize() - thisGrammar.status = 'ready' -else: - thisGrammar = None - -def unload(): - global thisGrammar - if thisGrammar: - thisGrammar.cancelMode() - thisGrammar.unload() - thisGrammar = None - -def changeCallback(type,args): - """calls back here, switches off numbers when microphone sleep or off - """ - if not thisGrammar: - return - if ((type == 'mic') and (args=='on')): - thisGrammar.openMicMode() - else: - thisGrammar.cancelMode() diff --git a/src/unimacro/DisabledGrammars/_tasks.py b/src/unimacro/DisabledGrammars/_tasks.py deleted file mode 100644 index fcfbf4c..0000000 --- a/src/unimacro/DisabledGrammars/_tasks.py +++ /dev/null @@ -1,1166 +0,0 @@ -__version__ = "$Rev: 606 $ on $sitegeate: 2014-01-27 13:37:09 +0100 (ma, 27 jan 2014) $ by $Author: quintijn $" -# This file is part of a SourceForge project called "unimacro" see -# http://unimacro.SourceForge.net and http://qh.antenna.nl/unimacro -# (c) copyright 2003 see http://qh.antenna.nl/unimacro/aboutunimacro.html -# or the file COPYRIGHT.txt in the natlink\natlink directory -# -# _tasks.py -# -# -# written by Quintijn Hoogenboom (QH softwaretraining & advies), -# july 2006 -# -# - -# -"""Do task switching (taskbar), - -And switch to Documents inside an application. - -Move tasks to other display other to a corner of the current monitor -""" -# -# -import natlink -import nsformat # for give name - -import time -import os -import os.path -import win32gui -import monitorfunctions -import sys -import types - -natut = __import__('natlinkutils') -natqh = __import__('natlinkutilsqh') -natbj = __import__('natlinkutilsbj') -from actions import doAction as action -from actions import doKeystroke as keystroke -from actions import setPosition -from actions import getPosition -import actions -import win32con -import win32api -language = natqh.getLanguage() -ICAlphabet = natbj.getICAlphabet(language=language) - -# center mouse after taskswitch (not good with XP and choice boxes in taskbar) - -ancestor=natbj.DocstringGrammar -class ThisGrammar(ancestor): - iniIgnoreGrammarLists = ['taskcount', 'documentcount', - #'switchapp', 'degrees', 'pixelcount', - 'switchapp', - #'sizecount','percentcount', 'directionplus', 'direction', - 'directionplus', 'namedtask'] - language = natqh.getLanguage() - name = "tasks" - # task commands in docstring form in the rule functions below - gramSpec = [""" - -# miscelaneous: - exported = ("switch file to") {switchapp}; - """] - - # include only if searchinothertask is True (via .ini file) (enable search commands = T) - searchRule = " exported = search ({taskcount}|{application}) | search ({taskcount}|{application});" - - def __init__(self): - """start the inifile and add to grammar if needed the searchRule - """ - self.startInifile() - #print 'enableSearchCommands: %s'% self.enableSearchCommands - if self.enableSearchCommands: - self.gramSpec.append(self.searchRule) - ancestor.__init__(self) - name = self.getName() - - - def initialize(self): - self.load(self.gramSpec) - self.switchOnOrOff() # initialises lists from inifile, and switches on - # if all goes well (and variable onOrOff == 1) - self.taskCounts = list(range(1, self.maxTaskNumber+1)) - self.documentCounts = list(range(1, self.maxDocumentNumber+1)) - # call for extra spoken form with difficult numbers - # needs self.stripSpokenForm in gotResults... function!!! - #self.addSpokenFormNumbers(self.taskCounts) - self.setNumbersList('taskcount', self.taskCounts) - self.setNumbersList('documentcount', self.documentCounts) - self.setList('switchapp', self.switchApps) - self.emptyList('namedtask') # to be filled with task name command - #for moving the window:schakel in taken - #self.pixelCounts = range(1, 21) + range(20, 201, 10) - #self.setNumbersList('pixelcount', self.pixelCounts) - #self.degreeCounts = range(0, 361,10) - #self.setNumbersList('degrees', self.degreeCounts) - #self.sizeCounts = range(1,21) - #self.setNumbersList('sizecount', self.sizeCounts) - #self.percentCounts = range(10,101,10) - #self.setNumbersList('percentcount', self.percentCounts) - self.namedtaskDict = {} # name -> hndle dict - # the spoken forms are the values of the inifile - # the keys of the inifile (fixed) are the resulting directions to be - # worked with - # for the task position etc commands: - self.directionsplus = self.iniGetInvertedDict('directionplusreverse') - self.setList('directionplus', list(self.directionsplus.keys())) - self.winkeyDown = 0 # for keeping down in stacked taskbar itemsals je zo graag -#left|up|right|down|lefttop|righttop|rightbottom|leftbottom; - self.switchOnOrOff() # initialises lists from inifile, and switches on - # if all goes well (and variable onOrOff == 1) - print('IniGrammar tasks, all lists initialized...') - - def iniGetInvertedDict(self, section): - """get all the values as keys, and the keys as values - values are separated by ; to are read in as a list - """ - D = {} - keys = self.ini.get(section) - if not keys: - raise ValueError('Grammar %s: no keys in inifile section [%s] (inifile: %s)'% - (self.name, section, self.ini._name)) - for k in keys: - values = self.ini.getList(section, k) - if values: - for v in values: - if v: - D[v] = k - else: - D[k] = k - return D - - def gotBegin(self,moduleInfo): - if self.checkForChanges: - self.checkInifile() # refills grammar lists and instance variables - if self.winkeyDown: - className = natqh.getClassName() - if className != 'TaskListThumbnailWnd': - print('tasks, call cancelmode from gotBegin') - self.cancelMode() - if self.makeTaskNamesPythonw and moduleInfo and moduleInfo[0].endswith("pythonw.exe"): - wTitle = moduleInfo[1] - if wTitle.find(" --- ") > 0: - self.addTaskNameToDict(moduleInfo) - - def gotResultsInit(self, words, fullResults): - self.fullResults = fullResults - # for the move commands: - self.directionplus = None # for position, stretch, shrink - self.units = None - self.amount = None - self.taskmoveresize = None # also "position" (see gotResults) - self.hadStartMenu = 0 - self.letters = None - self.app = None - self.namedictated = "" # for naming a window - self.giveName = None # for the hndle when naming a window - ### here come the docstring like rules: - ### - - def rule_startmenu(self, words): - """start menu [{startmenucommands}] - """ - print('got start menu') - if self.hasCommon(words[0], 'start'): - self.hadStartMenu = 1 - Act = self.getFromInifile(words[-1], 'startmenucommands') - if Act: - self.hadStartMenu = 0 # no action in gotResults, doing it here - self.doStartMenu() - action(Act) - - def doStartMenu(self): - """give the start menu - """ - action("SSK {ctrl+esc}") - - def rule_taskswitch(self, words): - """#commands for switching tasks: - task ({taskcount}|{taskcount}|{application}|{application}|back|{namedtask}) - """ - #print 'got taskswitch: %s'% words - #switch to a task by number, application or Back - #leave the mouse at 0.3 0.3 relative to the top - countOrApp = words[1] - #print 'goto task, countOrApp: %s'% countOrApp - result = self.gotoTask(countOrApp) - - if result: - prog, title, topchild, classname, hndle = natqh.getProgInfo() - if prog == 'explorer' and not title: - return # no centermouse! - if self.centerMouse and not self.nextRule: - natqh.Wait() - natqh.doMouse(1, 5, 0.3, 0.3, 0, 0) # relative in client area, no clicking - else: - print('_tasks, could not switch to task: %s'% countOrApp) - - - def rule_subtask(self, words): - """# commands for going to a subtask in a stacked taskbar - window {n1-10} | {firstlast} window - """ - className = natqh.getClassName() - wNumList = self.getNumbersFromSpoken(words) # returns a string or None - if wNumList: - wNum = wNumList[0] - else: - wNum = self.getFromInifile(words, 'firstlast') - if not wNum: - print('tasks, rule subtaks, no window number found') - return - - #print 'tasks, subtask: %s'% wNum - if className == "TaskListThumbnailWnd": - #print 'got subtask, alternative window: %s'% wNum - self.doAlternativeClick(className, wNum) - - if self.centerMouse and not self.nextRule: # so last rule of the recognition - natqh.doMouse(1, 5, 0.3, 0.3, 0, 0) - - def rule_numbereddocument(self, words): - """# go to a numbered document - document ({documentcount} [{documentaction}] | {documentaction}) - """ - count = self.getNumberFromSpoken(words[1]) # returns a string or None - if count: - #print 'goto task, countOrApp: %s'% countOrApp - result = self.gotoDocument(count) - - if result: - if self.centerMouse: - natqh.Wait() - natqh.doMouse(1, 5, 0.3, 0.3, 0, 0) # relative in client area, no clicking - else: - prog, title, topchild, classname, hndle = natqh.getProgInfo() - print('_tasks, could not switch to document: %s (program: %s)'% (count, prog)) - - if words[1] == words[-1]: - return - - Act = self.getFromInifile(words[-1], 'documentaction') - print('words[-1]: %s, Action: %s'% (words[-1], Act)) - if Act: - action(Act) - - def rule_relativedocument(self, words): - """# go to a relative document (previous, next, also with counts) - (next|previous) document [{n2-10}] [{documentaction}] - """ - hadNext = self.hasCommon(words[0], 'next') - count = self.getNumberFromSpoken(words) or 1 - if hadNext: - for i in range(count): - action("<>") - else: - for i in range(count): - action("<>") - - if words[1] == words[-1]: - # no document action - return - - Act = self.getFromInifile(words[-1], 'documentaction') - print('words[-1]: %s, Action: %s'% (words[-1], Act)) - if Act: - action(Act) - - def rule_relativedocumentsaction(self, words): - """# do action on more (relative) documents (previous, next, also with counts) - [(next|previous)] {n1-20} documents {documentaction} - """ - nextPrevAction = "" - hadPrevious = "" - hadNext = self.hasCommon(words[0], 'next') - if hadNext: - nextPrevAction = "<>" - else: - hadPrevious = self.hasCommon(words[0], 'previous') - if hadPrevious: - nextPrevAction = "<>" - - count = self.getNumberFromSpoken(words[0:2]) # returns a string or None - if not count: - print('_tasks, relativedocuments, count expected, got %s'% words[1]) - - if hadNext: - print('next, go one doc forward') - action(nextPrevAction) - else: - print('previous, go %s docs back'% count) - ## cycle n times: - for i in range(count): - action(nextPrevAction) - - Act = self.getFromInifile(words[-1], 'documentaction') - if not Act: - print('_tasks, relativedocuments, action expected, got %s'% words) - return - for i in range(count): - print('do action %s (%s times)'% (Act, count)) - action(Act) - - def gotResults_searchinothertask(self, words, fullResults): - ## rule for searching in another task, activated only if ... - - t = time.time() - searchWord = self.getSelectedText() - print('searchWord from getSelectedText: %s'% searchWord) - if not searchWord: - searchWord = action("SELECTWORD") - if not searchWord: - print('_tasks, searchinothertask: could not select text') - return - t1 = time.time() - print('searchword: %s (%.2f)'% (searchWord, t1-t)) - countOrApp = words[1] - #print 'switch to task: %s'% countOrApp - result = self.gotoTask(countOrApp) - if result is None: - print('_tasks, could not switch to task: %s'% countOrApp) - return - print('result after taskswitch: %s'% repr(result)) - t2 = time.time() - - prog, title, topchild, classname, hndle = progInfo = result - #print 'switched to "%s" (%.2f)'% (prog, t2-t1) - - - if prog == 'explorer' and not title: - return # no centermouse! - if self.centerMouse: - natqh.Wait() - natqh.doMouse(1, 5, 0.3, 0.3, 0, 0) # relative in client area, no clicking - - natqh.Wait() - # now do the postprocessing - print('postprocessing for search: %s in app: %s'% (searchWord, prog)) - if prog in ['chrome', 'firefox','iexplore']: - phrase = '"%s" site:nl'% searchWord - keystroke("{ctrl+k}") - keystroke(phrase + "{enter}") - elif prog == 'dictionaryworkbench': - # hardcoded for Arnoud - keystroke('{ctrl+f}') - action("SCLIP %s"% searchWord) - keystroke('{enter}') - else: - #t3 = time.time() - action("<>", progInfo=progInfo) - #t4 = time.time() - keystroke(searchWord, progInfo=progInfo) - #t5 = time.time() - action("<>", progInfo=progInfo) - #t6 = time.time() - #print 'after searchaction: %s (%.2f, %.2f, %.2f, %.2f)'% (searchWord, t3-t2, - # t4-t3, t5-t4, t6-t5) - - - def subrule_before(self, words): - """#optional word here in front of command: - Here - """ - action("CLICK") - natqh.visibleWait() - #action("CLICKIFSTEADY") - - def importedrule_dgndictation(self, words): - # for giving a window a name - self.namedictated = nsformat.formatWords(words, state=-1)[0] - - - def rule_taskaction(self, words): - '( | | task)({taskaction}| "give name" |)' - - # do a taskaction to the current task, or one of the - # numbered/named tasks or task back - #print 'got taskaction: %s'% words - actions = self.ini.get('taskaction') - act = self.hasCommon(words, actions) - giveName = self.hasCommon(words, "give name") - #if self.app == "messages": - # print 'action for messages: %s'% act - # if act == 'refresh': - # self.doTaskAction('close') - # print 'new messages window' - # return - if giveName: - hndle = natlink.getCurrentModule()[2] - self.giveName = hndle - elif act: - self.doTaskAction(act) - else: - print('thistask in _general, no valid action', words) - - prog, title, topchild, classname, hndle = natqh.getProgInfo() - if prog == 'explorer' and not title: - return # no centermouse! - - if self.centerMouse: - natqh.doMouse(1, 5, 0.3, 0.3, 0, 0) - - def subrule_closemultiple(self, words): - """close (all|other) | (all|other) close - """ - # note the grammar alternatives, eg in Dutch the translation of - # all close (alles sluiten) is more convenient. - if not self.lastTaskCount: - print('_tasks, close all | close multiple only works with a numbered task') - return - all = self.hasCommon(words, "all") - multiple = self.hasCommon(words, "multiple") - if all: - action("MP 2, 0, 0, right; VW; {up}{enter}; VW") - self.gotoTask("back") - - elif multiple: - # close as long as special stacked window is found - mousePos = natqh.getMousePosition() - if mousePos is None: - raise ValueError("could not get mouse position") - x, y = mousePos - className = natqh.getClassName() - wNum = -1 # last window of stacked windows... - #print 'tasks, subtask: %s'% wNum - while className == "TaskListThumbnailWnd": - #print 'got subtask, alternative window: %s'% words - self.doAlternativeClick(className, wNum) - action("<>") - action("VW; MP 0, %s, %s"% mousePos) - className = natqh.getClassName() - self.gotoTask(self.lastTaskCount) - if self.centerMouse: - natqh.doMouse(1, 5, 0.3, 0.3, 0, 0) - - - def gotoTask(self, countOrApp): - """go to the specified task, by number or application name, return proginfo, or None if task was not found - - """ - self.lastTaskCount = None - if type(countOrApp) in (bytes, str): - countBack = self.getNumberFromSpoken(countOrApp, self.taskCounts) # returns a string or None - elif isinstance(countOrApp, int): - countBack = countOrApp - hasMousePos = 0 - appList = self.ini.get('application') -## print 'appList: %s'% appList - if type(countOrApp) in (bytes, str) and self.hasCommon(countOrApp, 'back'): - action('SSK {Alt+Tab}') - return 1 - elif countOrApp in self.namedtaskDict: - hndle = self.namedtaskDict[countOrApp] - result = natqh.SetForegroundWindow(hndle) - if not result: - print('switch to %s failed, delete name: %s'% (hndle, countOrApp)) - del self.namedtaskDict[countOrApp] - self.setList('namedtask', list(self.namedtaskDict.keys())) - return - else: - return result - elif countBack: - t = time.time() - self.lastTaskCount = countBack - if self.doTasksWithWindowsKey: - self.goto_task_winkey(countBack) - else: - action('TASK %s'% countBack) - result = natqh.getProgInfo() - #print 'after action task %s, time: %.2f'% (countBack, (time.time()-t)) - return result - elif countOrApp in appList: - value = self.ini.getList('application', countOrApp) - if len(value) == 1: - app = value[0] - self.app = app - result = action("BRINGUP %s"% app) - return result -## print 'after bringup: %s'% app - elif len(value) == 2: - #application is known, but click by number!! - appName = value[0] - countBack = value[1] - self.lastTaskCount = countBack - if self.doTasksWithWindowsKey: - self.goto_task_winkey(countBack) - else: - action('TASK %s'% countBack) - for i in range(30): - # 40 x 0.1: 4 seconds... - prog, title, topchild, classname, hndle = natqh.getProgInfo() - if prog == appName: break - className = natqh.getClassName() - if className == "TaskListThumbnailWnd": return 1 # more items already available - natqh.Wait() - else: - print('application not detected in foreground: %s'% appName) - return - else: - print('_tasks, no valid entry for gotoTask: %s'% countOrApp) - return - result = natqh.getProgInfo() - - def gotoDocument(self, count): - """go to the specified document, by number or application name, return proginfo, or None if task was not found - - """ - result = action('DOCUMENT %s'% count) - print('result of gotoDocument %s: %s'% (count, result)) - return result - - def goto_task_winkey(self, number): - """switch to task with number, via the windows key""" - ## print 'action: goto task: %s'% number - prog, title, topchild, classname, hndle = natqh.getProgInfo() - if prog == 'explorer' and not title: - keystroke('{esc}') - natqh.shortWait() - try: - count = int(number) - except ValueError: - print('goto_task_winkey, invalid number: %s'% number) - return - if not count: - print('goto_task_winkey, invalid number: %s'% number) - return - elif count == 10: - count=0 - elif count > 10: - print('goto_task_winkey, pass on to "TASK %s", number > 9'% count) - return action('TASK %s'% count) - - self.doWinKey('b') - actions.do_VW() - self.doWinKey(str(number)) - print('self.winkeyDown: %s'% self.winkeyDown) - - - def rule_taskposition(self, words): - """ - #commands for positioning (moving) and resizing tasks: - (|task) position - """ - # position task in one of the directions, width/height - # did also optional percent with switched off for the moment - # optional percentage of work area - self.taskmoveresize = 'position' - print('----task position') - - def rule_taskmove(self, words): - """( | task) move ; - """ - - # removed all the angle, pixels, centimeters, inches, percent out, too complicated for daily use I think... - # optional a specification - self.taskmoveresize = 'move' - print('----task move') - - #def rule_taskresize(self, words): - # """( | (task)) (stretch|shrink) - # (|) - # [||||] - # """ - # # resize a task in direction or angle - # # with optional specification - # if self.hasCommon(words, 'stretch'): - # self.taskmoveresize = 'stretch' - # if self.hasCommon(words, 'shrink'): - # self.taskmoveresize = 'shrink' - # print '----task resize: %s'% self.taskmoveresize - # # action in gotResult - - def rule_taskresizeinfo(self, words): - """give resize info - """ - winHndle = win32gui.GetForegroundWindow() - canBeResized = monitorfunctions.window_can_be_resized(winHndle) - print('resize info %s'% canBeResized) - - - # rules inside position, move, stretch, shrink: - # too precise, can be switched on again later... - #def subrule_angle(self, words): - # """ - # #directional specifications: - # {degrees} degrees - # """ - # #get the move or resize angle - # deg = self.getNumberFromSpoken(words[0]) - # self.directionplus = deg%360 - # print 'angle/direction: %s'% self.directionplus - - def subrule_directionplus(self, words): - '{directionplus}' - #get the direction - direction = words[0] - if direction in self.directionsplus: - self.directionplus = self.directionsplus[direction] - else: - self.directionplus = direction - print('direction: (plus) %s'% self.directionplus) - - def rule_monitorfocus(self, words): - 'monitor {monitors}' - # put focus on monitor - # target is the index of the MONITOR_HNDLES list of monitorfunctions.py. - # for 3 monitors 0, 1 or 2. Which is which has to be tried, hopefully the - # list is consistent - monitorIndex = int(self.getFromInifile(words[1], 'monitors')) - # print 'ask for monitor: %s'% monitorIndex WORK AREA - rect = monitorfunctions.get_monitor_rect_work(monitorIndex) - # print 'rect: %s'% repr(rect) - if not rect: - print('rule_monitorfocus, no position rectangle found') - return - mx, my = natqh.relToCoord(0.5, rect[0], rect[2]), natqh.relToCoord(0.01, rect[1], rect[3]) - natqh.doMouse(0, 0, mx, my, mouse='left') - natqh.visibleWait() - # relative and relative to current monitor work area: - natqh.doMouse(1, 4, 0.5, 0.5, mouse="noclick") - natqh.visibleWait() - # mx, my = natqh.relToCoord(0.5, rect[0], rect[2]), natqh.relToCoord(0.5, rect[1], rect[3]) - # natqh.doMouse(0, 0, mx, my, mouse='noclick') - # actions.doAction("RMP(3, 0.3, 0.3, mouse='noclick')") - - #def subrule_pixels(self, words): - # """ - # # size specifications: - # {pixelcount} | {pixelcount} pixels - # """ - # #get the amount in pixels (optional word) - # amountList = self.getNumberFromSpoken(words) - # if len(amountList) == 1: - # self.amount = amountList[0] - # else: - # raise ValueError("task grammar, rule pixels, more amounts found: %s"% amountList) - # self.units = 'pixels' - # print 'pixels: %s'% self.amount - # - #def subrule_centimeters(self, words): - # '{sizecount} centimeters' - # """get the amount in centimeters""" - # nCm = self.getNumberFromSpoken(words[0]) - # self.units = 'pixels' - # self.amount = nCm * self.dotsperinch * 1.0 / 2.54 + 0.5 - # print 'pixels(%s cm): %s'% (nCm, self.amount) - # - #def subrule_millimeters(self, words): - # '{sizecount} millimeters' - # #get the amount in millimeters - # nMm = self.getNumberFromSpoken(words[0]) - # self.units = 'pixels' - # self.amount = nMm * self.dotsperinch * 1.0 / 25.4 + 0.5 - # print 'pixels(%s mm): %s'% (nMm, self.amount) - # - #def subrule_inches(self, words): - # '{sizecount} inches' - # #get the amount in inches - # nInches = self.getNumberFromSpoken(words[0]) - # self.units = 'pixels' - # self.amount = nInches * self.dotsperinch - # print 'pixels(%s mm): %s'% (nInches, self.amount) - - def rule_gettaskposition(self, words): - """ - #commands for recording taskbar positions: - get task position {taskcount} - """ - # getting the task positions (use with 1 and with another number) - # position mouse on task number or clock and speak the command - # june 2016: removed the obsolete clock commands. - # first time only, or after changes of taskbar position - count = self.getNumberFromSpoken(words[-1]) - x, y = natlink.getCursorPos() - if count in self.taskCounts: - print('%s, setting task position: %s'% (self.name, count)) - else: - print('%s, not a valid "count" for setting task position: %s'% (self.name, count)) - return - if count == 1: - print('setting mouseX1: ', x) - print('setting mouseY1: ', y) - setPosition('mousex1', x) - setPosition('mousey1', y) - else: - mousex1 = getPosition('mousex1') - mousey1 = getPosition('mousey1') - - mouseXdiff = int((x - mousex1 )/(count-1)) - mouseYdiff = int((y - mousey1 )/(count-1)) - print('setting mouseXdiff: ', mouseXdiff) - print('setting mouseYdiff: ', mouseYdiff) - setPosition('mousexdiff', mouseXdiff) - setPosition('mouseydiff', mouseYdiff) - - def rule_getdocumentposition(self, words): - """ - #commands for recording a document position, application specific - get document position {documentcount} - """ - # getting the task positions (use with 1 and with another number) - # position mouse on task number or clock and speak the command - # first time only, or after changes of taskbar position - prog, title, topchild, classname, hndle = natqh.getProgInfo() - if not prog: - print('%s, no valid program for setting document position: %s (title:%s)'% (self.name, prog, title)) - return - count = self.getNumberFromSpoken(words[-1]) - x, y = natlink.getCursorPos() - if count in self.documentCounts: - print('%s, setting document position %s for program: %s'% (self.name, count, prog)) - else: - print('%s, cannot set document position "%s" for program: %s (invalid count)'% (self.name, count, prog)) - return - if count == 1: - print('setting mouseX1: ', x) - print('setting mouseY1: ', y) - setPosition('mousex1', x, prog=prog) - setPosition('mousey1', y, prog=prog) - else: - mousex1 = getPosition('mousex1', prog=prog) - mousey1 = getPosition('mousey1', prog=prog) - - mouseXdiff = int((x - mousex1 )/(count-1)) - mouseYdiff = int((y - mousey1 )/(count-1)) - print('setting mouseXdiff: ', mouseXdiff) - print('setting mouseYdiff: ', mouseYdiff) - setPosition('mousexdiff', mouseXdiff, prog=prog) - setPosition('mouseydiff', mouseYdiff, prog=prog) - - - # - def gotResults_fileswitch(self, words, fullResults): - """switch file to the named application - mark cursor - close in current app - open in new app - goto top - goto cursor - - if filename cannot be got the process is stopped - - """ - fileName = actions.getPathOfOpenFile() - if fileName: - print('fileName: %s'% fileName) - else: - self.DisplayMessage('cannot switch, filename cannot be established') - return - - while fileName.endswith("*"): - fileName = fileName[:-1] - actions.putCursor() - action("<>") - action("W") - print("saved, now close: %s"% fileName) - action("<>") - newApp = words[-1] - newApp = self.ini.get('application', newApp, newApp) - - if not action("BRINGUP %s"% newApp): - self.DisplayMessage('cannot switch, application %s cannot be brought to front'% newApp) - return - - # fileopen in emacs relies on maximised state of emacs, cannot be sure here: - if newApp in ('emacs', 'voicecode'): - action("{ctrl+x}{ctrl+f}; {shift+home}{del}") - else: - action("<>") - action("W") - keystroke(os.path.normpath(fileName)) - action("VW") - keystroke("{enter}") - action("<>") - actions.findCursor() - action("<>") - - def gotResults_convertfile(self, words, fullResults): - """copy file and change \n\r in \n or vice versa - - mark cursor - cut all - convert clipboard - paste - goto home - goto cursor - - """ - actions.putCursor() - action("CLIPSAVE") - action("<><>") - t = natlink.getClipboard() - t = self.convertString(t, words[-1]) - natqh.setClipboard(t) - action("<>") - action("<>") - actions.findCursor() - action("<>") - - def gotResults(self, words, fullResults): - """actions for task move, resize, position done here - - relevant data collected in other gotResult_... functions - - """ - if self.giveName: - if self.namedictated: - self.namedtaskDict[self.namedictated] = self.giveName - self.setList('namedtask', list(self.namedtaskDict.keys())) - print('name "%s" can now be used for switching to a task'% self.namedictated) - else: - print('giveName, no self.namedictated given...') - - if self.hadStartMenu: - self.doStartMenu() - if self.letters: - keystroke(self.letters) - - if self.taskmoveresize: - print('taskmoveresize: %s'% self.taskmoveresize) - winHndle = win32gui.GetForegroundWindow() - #print 'amount: %s'% self.amount - #print 'units: %s'% self.units - if self.directionplus in self.directions: - direction = self.directions[self.directionplus] - else: - direction = self.directionplus - print('direction spoken: %s, direction taken: %s'% (self.directionplus, direction)) - canBeResized = monitorfunctions.window_can_be_resized(winHndle) - if self.taskmoveresize == 'position': - self.doTaskPositionCommand(winHndle, canBeResized, direction, self.amount, self.units) - else: - # move, stretch or shrink: - if self.amount: - amount = self.amount - units = self.units or 'pixels' - elif self.taskmoveresize == 'move': - amount = 1 - units = 'relative' - elif self.taskmoveresize == 'stretch': - amount = 1 - units = 'relative' - elif self.taskmoveresize == 'shrink': - amount = 0.5 - units = 'relative' - else: - print('_tasks, gotResults, invalid taskmoveresize: %s'% self.taskmoveresize) - return - - print('amount (adjusted): %s'% amount) - print('units: (adjusted) %s'% units) - - try: - func = getattr(monitorfunctions, '%s_window'% self.taskmoveresize, None) - if func: - #print 'doing func: %s'% func - func(winHndle, direction=self.directionplus, amount=amount, units=units) - else: - print('invalid value for taskmoveresize: %s (could not find function)'% self.taskmoveresize) - except ValueError: - print('error in monitorfunctions.%s_window'% self.taskmoveresize) - print(sys.exc_info()[1]) -#keepinside=None, keepinsideall=1, monitor=None): - - def addTaskNameToDict(self, moduleInfo): - """add name of task to the namedTasDict is requirements are met - - no return, change is made in namedTaskDict and the setList is done as well - - 1. must be pythonw (already tested in gotBegin) - 2. title must hold " --- " (applications of QH) - 3. check for abbrevs list in spokenforms, to make the command pronouncable - - """ - prog, title, hndle = moduleInfo - if title.find(" --- ") == -1: - return - name = title.split()[0] - name = name.strip("~ ") - - if not name: - return - gotChanges = None - - name = self.spokenforms.abbrev2spoken.get(name, name) - if name and type(name) == list: - for n in name: - gotChanges = self.checkNamedTaskDict(n, hndle) or gotChanges - else: - gotChanges = self.checkNamedTaskDict(name, hndle) - if gotChanges: - print('set namedtask list: %s'% list(self.namedtaskDict.keys())) - self.setList('namedtask', list(self.namedtaskDict.keys())) - - - def checkNamedTaskDict(self, name, hndle): - """insert name, hndle in self.namedTaskDict if not yet there - - return 1 if change has been made. - - """ - if self.namedtaskDict.get(name, None) == hndle: - return # name already in dict and same hndle - self.namedtaskDict[name] = hndle - return 1 - - def doWinKey(self, keys, keepdown=None): - """do a winkey and return the window info of the resulting window - """ - winkey = win32con.VK_LWIN # 91 - keyup = win32con.KEYEVENTF_KEYUP # 2 - win32api.keybd_event(winkey, 0, 0, 0) # key down - try: - actions.do_SSK(keys) - actions.do_VW() - classInfo = natqh.getClassName() - finally: - if classInfo == 'TaskListThumbnailWnd': - #print 'keep logo key down' - self.winkeyDown = 1 - else: - win32api.keybd_event(winkey, 0, keyup, 0) # key up - - - - # taken from _shownumbersplus, go to a subtask in stacked taskbar - # number from 0, (in _shownumbersplus first window is click 0) - def doAlternativeClick(self, className, num): - """instead of click perform another (keystrokes) action - - if self.doTasksWithWindowsKey, do this with repeated winkey clicks - """ - taskNum = self.lastTaskCount - if type(num) in (bytes, str): - num = int(num) - if className == "TaskListThumbnailWnd": - #print 'tasks, doAlternative click: %s'% num - if self.doTasksWithWindowsKey: - if not (taskNum and self.winkeyDown): - print('cannot complete windows command: taskNum: %s, winkeyDown: %s'% (taskNum, self.winkeyDown)) - self.cancelMode() - return - if num > 1: - keystr = str(taskNum) - for i in range(num-1): - actions.do_SSK(keystr) - elif num < 0: - num2 = -num - keystr = '{shift+%s}'% taskNum - for i in range(num2): - actions.do_SSK(keystr) - self.cancelMode() - return - - # mode with mouse on taskbar position: - taskbarPosition = monitorfunctions.get_taskbar_position() # notices changes on the fly! - # which way to scroll through a stack of taskbar buttons: - initialKeys = dict(left='{down}', top='{right}', - right='{left}{down}', bottom='{right}') - scrollKeys = dict(left='down', top='right', - right='down', bottom='right') - initialKeysReverse = dict(right='{left}', bottom='{left}', - left='{right}', top='{left}') - scrollKeysReverse = dict(right='up', bottom='left', - left='up', top='left') - try: - if num > 0: - initial = initialKeys[taskbarPosition] - scrollKey = scrollKeys[taskbarPosition] - elif num < 0: - initial = initialKeysReverse[taskbarPosition] - scrollKey = scrollKeysReverse[taskbarPosition] - num = -num - else: - raise ValueError("_tasks, doAlternativeClick, number may NOT be 0") - except KeyError: - print('key not found "taskbarPosition": %s'% taskbarPosition) - return - # go to first of popup windows (depending on taskbar location) - #print 'taskbarPosition: %s'% taskbarPosition - #print 'initial: %s, scroll: %s'% (initial[1:], scrollKey) - action(initial) - if num > 1: - num -= 1 - action('{%s %s}'% (scrollKey, num)) - action('{enter}') - else: - print('should not call doAlternativeClick for className: %s'% className) - - - def doTaskPositionCommand(self, winHndle, canBeResized, direction, amount, units): - """do the task position command with enclosed parameters - """ - if amount and units == 'percent': - amount = amount / 100.0 - elif amount: - print('amount: %s'% amount) - else: - amountx = self.splitLeftRight - amounty = self.splitTopDown - xwidth = ywidth = 1.0 - if canBeResized: - print('setting default pos to 0.0') - xpos = ypos = 0.0 - else: - print('no resize, setting default pos to 0.5') - xpos = ypos = 0.5 - if direction.find('left') >= 0: - xpos = 'left' - xwidth = amountx - elif direction.find('right') >= 0: - xpos = 'right' - xwidth = 1.0 - amountx - elif direction.startswith('center'): - xpos = 'center' - if amountx >= 0.5: - xwidth = amountx - else: - xwidth = 1.0 - amountx - - if direction.find('up') >= 0: - ypos = 'up' - ywidth = amounty - elif direction.find('down') >= 0: - ypos = 'down' - ywidth = 1.0 - amounty - elif direction.endswith('center'): - ypos = 'center' - if amounty >= 0.5: - ywidth = amounty - else: - ywidth = 1.0 - amounty - - if not canBeResized: - xwidth = ywidth = None - print('restore_window:pos: %s, %s, width: %s, %s'% \ - (xpos, ypos, xwidth, ywidth)) - func = monitorfunctions.restore_window - func(winHndle, xpos=xpos, ypos=ypos, - xwidth=xwidth, ywidth=ywidth) - # - # - #def convertString(self, t, toCode): - # """convert to unix style (\n) or dos/windows style \n\r sucks...""" - # CR = chr(10) - # LF = chr(13) - # CRLF = CR + LF - # CRCRLF = CR + CR + LF - # if toCode == 'unix': - # return t.replace(CRLF, LF) - # elif toCode in ('windows', 'dos'): - # t = t.replace(LF, CRLF) - # t = t.replace(CRCRLF, CRLF) - # t = t.replace(CRLF+CRLF, CRLF) - # return t - - def gotResults_removecursor(self, words, fullResults): - """goto marked cursor, in case is was left in file switch actions""" - actions.findCursor() - - def doTaskAction(self, actionWord, mouseOnPosition=0): - """do action on - - if mouseOnPosition, instead of {alt+space} a right click is done - """ - if actionWord: - act = self.ini.get('taskaction', actionWord) - if act: - #natqh.visibleWait() - action(act) - else: - print('no action for taskaction: %s'% actionWord) - - - def fillInstanceVariables(self): - """fills the necessary instance variables - - positions should be in actions.ini, and can be got by the "task position" commands - - """ - self.maxTaskNumber = self.ini.getInt('general', 'max task number') or 20 - self.maxWindowNumber = self.ini.getInt('general', 'max window number') or 9 - self.maxDocumentNumber = self.ini.getInt('general', 'max document number') or 20 - self.centerMouse = self.ini.getBool('general', 'center mouse') - #self.dotsperinch = self.ini.getInt('general', 'screen dots per inch') or 90 - - self.doTasksWithWindowsKey = self.ini.getBool('general', 'do taskswitch with windows key') - if self.doTasksWithWindowsKey: - print('do taskswitch with windows key enabled') - # positioning not in middle (for Arnoud): - self.splitLeftRight = self.ini.getFloat('general', 'split left right') or 0.5 - self.splitTopDown = self.ini.getFloat('general', 'split top down') or 0.5 - - # search commands (for Arnoud): - self.enableSearchCommands = self.ini.getBool('general', 'enable search commands') - if self.enableSearchCommands: - print('_task, enable search commands') - - # special windows from pythonw (QH) - self.makeTaskNamesPythonw = self.ini.getBool('general', 'make task names pythonw') - if self.makeTaskNamesPythonw: - print('_task, make task names pythonw (option for QH)') - - allApps = self.ini.get('application') - - # contstruct - switchApps = self.ini.getList('general', 'switchapps') - self.switchApps = [] - if switchApps: - # construct items for switchApps list, must be either - # the keyword or the value of one of the items of - # allApps (the list of applications in the inifile - - allAppsDict = dict([(k, self.ini.get('application', k)) for k in allApps]) - - for sApp in switchApps: - if sApp in allApps: - self.switchApps.append(sApp) - else: - foundSpoken = 0 - for k,v in list(allAppsDict.items()): - if v == sApp: - foundSpoken = 1 - self.switchApps.append(k) - if not foundSpoken: - print('application not valid for switchapps: "%s", no written or spoken form in section [applications])'% sApp) - - def getSelectedText(self): - """gets a copy of the selection, otherwise "" - """ - natqh.saveClipboard() - action("<>") - natqh.Wait() - t = natqh.getClipboard() - natqh.restoreClipboard() - return t.strip() - - def cancelMode(self): - # ending exclusive mode if in it, also ending the mode it is in - winkey = win32con.VK_LWIN # 91 - keyup = win32con.KEYEVENTF_KEYUP # 2 - if self.winkeyDown: - print('tasks, cancelMode, release WINKEY') - win32api.keybd_event(winkey, 0, keyup, 0) # key up - self.winkeyDown = 0 - - -# standard stuff Joel (adapted for possible empty gramSpec, QH, unimacro) -thisGrammar = ThisGrammar() -if thisGrammar.gramSpec: - thisGrammar.initialize() -else: - thisGrammar = None - -def unload(): - global thisGrammar - if thisGrammar: thisGrammar.unload() - thisGrammar = None - -def changeCallback(type,args): - # not active without special version of natlinkmain: - if ((type == 'mic') and (args=='on')): - return # check WAS in natlinkmain... - if thisGrammar: - thisGrammar.cancelMode() diff --git a/src/unimacro/DisabledGrammars/firefox_browsing.py b/src/unimacro/DisabledGrammars/firefox_browsing.py deleted file mode 100644 index dc9bb86..0000000 --- a/src/unimacro/DisabledGrammars/firefox_browsing.py +++ /dev/null @@ -1,387 +0,0 @@ -__version__ = "$Rev: 606 $ on $Date: 2019-04-23 14:30:57 +0200 (di, 23 apr 2019) $ by $Author: quintijn $" -# This file is part of a SourceForge project called "unimacro" see -# http://unimacro.SourceForge.net and http://qh.antenna.nl/unimacro -# (c) copyright 2003 see http://qh.antenna.nl/unimacro/aboutunimacro.html -# or the file COPYRIGHT.txt in the natlink\natlink directory -# -# Firefox, numbers mode -# -# assumes Hint-a-Hint extension from Pekka Sillanpaa (mode = "hah" ) -# Or -# Mouseless Browsing extension from Rudolf Noe (mode = "mlb") -# -# set in line 61 below================================================ -# -# -# written by: Quintijn Hoogenboom (QH software, training & advies) -# -# the lists {n1-9}, {n1-20} are constructed in internal grammar functions -# -# the lists {pagecommands} and {tabcommands} in the inifile (edit firefox hah) -# -""" -This command grammar up to now is: - -get numbers | show numbers | toggle numbers -numbers off|cancel|clear numbers -choose # -choose # new tab|new window - -(# is a number that can go as high as 300) - -for going forward and back in pages (and refreshing pages): - -next page | previous page | refresh page -page back <1-20> | page forward <1-20> - -For tabbed browsing: - -previous tab | next tab | refresh tab | close tab -tab number # | tab number # close | tab number # refresh -""" - - -import natlink -natqh = __import__('natlinkutilsqh') -natut = __import__('natlinkutils') -natbj = __import__('natlinkutilsbj') -from actions import doAction as action -from actions import doKeystroke as keystroke - -# some fixed keystrokes: -getNumbers = dict(hah='{ctrl+,}', mlb='{NumKey.}') #keystrokes to get the numbers -Escape = dict(hah='{esc}', mlb='{esc}') -waitBeforeNewNumbers = 0.8 -visiblePause = 0.4 - -language = natqh.getLanguage() - -#SET THIS TO "hah" or "mlb": -mode = "mlb" - -ancestor = natbj.IniGrammar -class ThisGrammar(ancestor): - - try: - numberGram = natbj.numberGrammarTill999[language] - except KeyError: - print('take number grammar from "enx"') - numberGram = natbj.numberGrammarTill999['enx'] - - if language == "nld": - name = 'Faajer foks brouwsen' - else: - name = 'Firefox Browsing' - - gramSpec = """ - exported = (give|hide|toggle) numbers | - numbers on; - exported = (follow|focus|new) | - (follow) ('new tab' | 'context menu'|snelmenu); - exported = numbers off | clear numbers; - - exported = (next|previous|{pagecommands}) page | - page (back|forward) | page (back|forward) {n1-20} | - page {pagecommands} | - (next|previous) page | (next|previous) page {pagecommands}; - - exported = (next|previous) tab | (next|previous) tab {tabcommands} | - {tabcommands} (tab) | - tab {n1-30} | - tab (number|minus|number minus) {n1-30} | - tab {n1-30} {tabcommands} | - tab (number|minus|number minus) {n1-30} {tabcommands} | - tab {tabcommands}; - exported = {n2-20} tabs close; - exported = (update|refresh) numbers; - -#and the numbers grammar (0,...,999): -"""+numberGram - - def initialize(self): - self.prevHandle = -1 - self.load(self.gramSpec) - - def gotBegin(self,moduleInfo): - if not language: return - winHandle = moduleInfo[2] - if self.prevHandle == winHandle: - return - self.prevHandle = winHandle - if natqh.matchModule('firefox', modInfo=moduleInfo): - #print 'activate firefox %s mode'% mode - if self.checkForChanges: - print('firefox browsing (%s), checking the inifile'% self.name) - self.checkInifile() - - self.switchOnOrOff() - elif self.isActive(): - #print 'deactivate Firefox %s mode'% mode - self.deactivateAll() - - # Bij het initialiseren wordt de horizontale spatiejering uitgerekend. - # Er wordt van uitgegaan dat het venster niet te smal staat. - def gotResultsInit(self,words,fullResults): - """at start of actions""" - # just in case a button was kept down (with show card commands) - self.hadChoose = None - self.chooseSpecification = '' - self.number = '' - - - def gotResults_getnumbers(self,words,fullResults): - """works also if numbers already given, but cancels the loading of a page - - """ -## print 'getnumbers, doing: %s'% Escape + getNumbers - if mode == 'hah': - keystroke(Escape[mode]) - keystroke(getNumbers[mode]) - - def gotResults_update(self,words,fullResults): - """forces refresh of numbers on the page with MLB""" - keystroke('{alt+=}') - - - def gotResults_cancelnumbers(self,words,fullResults): - """also stops loading the page when not finished""" -## print 'cancel numbers, doing: %s'% Escape - if mode == 'hah': - keystroke(Escape[mode]) - else: - keystroke(getNumbers[mode]) - - def gotResults_navigatepages(self,words,fullResults): - """go to next or previous page(s) and refresh possibly""" -## print 'navigate pages: %s'% words - - dir = None - command = self.getFromInifile(words, 'pagecommands',noWarning=1) - - if self.hasCommon(words, ['next', 'verder', 'volgende', 'vooruit', 'forward']): - dir = 'right' - elif self.hasCommon(words, ['previous', 'terug', 'vorige', 'back']): - dir = 'left' - else: - print('no direction found in command: %s'% words) - - counts = self.getNumbersFromSpoken(words) - if counts: - count = counts[0] - else: - count = 1 -## print 'PAGES: dir: %s, count: |%s|, command: |%s|'% (dir, counlinker balkt, command) - if mode == 'hah': - keystroke(Escape[mode]) - - getNumbersAgain = 1 - if dir: - while count > 0: - count= count -1 - keystroke('{alt+ext%s}'%(dir)) - natqh.Wait(0.5) #0.3 seem too short for going back pages in Firefox - #elif count: - # print "Ctl + number doesnot work always!" - # keystroke('{ctrl+%s}'% count) - # natqh.Wait(0.3) - - if command: - action(command) - if command.lower().find('f5') > 0: - # refresh action: - getNumbersAgain = 1 - - # only get new numbers if no refresh was asked for - if getNumbersAgain and mode =="hah": - natqh.Wait(waitBeforeNewNumbers) - keystroke(getNumbers[mode]) - - def gotResults_navigatetabs(self,words,fullResults): - """switch to tabs in firefox - - goto numbered tab or to next|previous tab. optional command (refresh) - """ -## print 'navigate tabs: %s'% words - dir = None - minus = None - command = self.getFromInifile(words, 'tabcommands',noWarning=1) - - if self.hasCommon(words, ['next', 'verder', 'volgend','volgende']): - dir = 'pgdn' - elif self.hasCommon(words, ['previous', 'terug', 'vorig', 'vorige']): - dir = 'pgup' - elif self.hasCommon(words, ['minus', 'min']): - minus = 1 - - counts = self.getNumbersFromSpoken(words) - if counts: - count = counts[0] - else: - count = None - #print 'TABS: dir: %s, count: |%s|, command: |%s|'% (dir, count, command) - keystroke(Escape[mode]) - - getNumbersAgain = 1 - if dir: - keystroke('{ctrl+ext%s %s}'%(dir, count or '1')) - natqh.Wait(visiblePause) - elif count: - if mode == 'mlb': - if minus: - mbDonumber("01",'ctrl') - # need to wait: - natqh.Wait(visiblePause*2) - dir = 'pgup' - keystroke('{ctrl+ext%s %s}'%(dir, count or '1')) - natqh.Wait(visiblePause) - else: -## print 'go to tab: %s'% count - numberString = '%s%s'% (0,count) - mbDonumber(numberString,'ctrl') - else: - if minus: - print('not implemented in hah') - else: - keystroke('{ctrl+%s}'% count) - else: - getNumbersAgain = 0 - - if command: - natqh.Wait(visiblePause*2) - action(command) - - if command.lower().find('f5') > 0: - # refresh action: - getNumbersAgain = 0 - - if getNumbersAgain and mode =="hah": - natqh.Wait(waitBeforeNewNumbers) - keystroke(getNumbers[mode]) - - def gotResults_moretabsclose(self,words,fullResults): - """close more tabs in one commands - """ - n = self.getNumberFromSpoken(words[0]) - for i in range(n): - keystroke("{ctrl+w}") - - def gotResults_choose(self,words,fullResults): - w = words[0] - #print 'choose words: %s'% words - if not self.hadChoose: - self.hadChoose = 1 - self.waitForNumber('number') - - if self.hasCommon(words, ['focus']): - self.chooseSpecification = 'focus' - if self.hasCommon(words, ['new', 'nieuw', 'new tab', 'nieuw tabblad']): - self.chooseSpecification = 'new' - if self.hasCommon(words, ['context menu', 'snelmenu']): - self.chooseSpecification = 'context menu' - - def gotResults(self,words,fullResults): - - # step 5, in got results collect the number: - # only necessary in this grammar for collecting the choose command - if not self.hadChoose: - return - self.collectNumber() - print('%s: dictated number: %s'% (self.name, self.number)) - - if mode =="hah": -## print 'hah go to number:',self.number - keystroke("%s"% self.number) - # natqh.Wait(visiblePause) - keystroke(getNumbers[mode]) - print('firefox browsing with hah obsolete') - return - if self.hadChoose in ['focus']: - pass - elif not self.hadNew: - keystroke("{enter}") - elif self.hasCommon(self.hadNew,['tab', 'tabblad']): - keystroke("{numpadd++}") - elif self.hasCommon(self.hadNew, ['venster', 'window']): - keystroke("{shift+enter}") - elif self.hasCommon(self.hadNew, ['menu', 'snelmenu']): - keystroke("{shift+shift}") - return - elif self.hasCommon(self.hadNew,['new', 'nieuw']): - keystroke("{numpadd++}") - return - else: - print('unknown word in command: %s'% self.hadNew) - keystroke("{enter}") - - natqh.Wait(waitBeforeNewNumbers) - keystroke(getNumbers[mode]) - - elif mode == "mlb": - keystroke("{esc}") - if self.chooseSpecification == 'new': - #print 'firefox MLB: open in new tab' - mbDonumber(self.number,'alt') - elif self.chooseSpecification in ['focus', 'context menu']: - #print 'firefox MLB: show focus' - mbDonumber(self.number) - keystroke("{shift}") - if self.chooseSpecification == 'context menu': - keystroke("{shift+f10}") - else: - mbDonumber(self.number,'ctrl') - -lookupdict = dict(enter=13) - -def getKeyCode(k): - """get the code of a key""" - if k[0] == '{': - return lookupdict[k[1:-1]] - elif k in utilsqh.lowercase: - return ord(k.upper()) - elif k in utilsqh.uppercase: - return ord(k) - elif k in utilsqh.digits: - return 96 + int(k) - -modifiers = { - 'ctrl': ((natut.wm_keydown, natut.vk_control, 1), (natut.wm_keyup, natut.vk_control, 1)), - 'shift': ((natut.wm_keydown, natut.vk_shift, 1), (natut.wm_keyup, natut.vk_shift, 1)), - 'alt': ((natut.wm_syskeydown, natut.vk_menu, 1), (natut.wm_syskeyup, natut.vk_menu, 1))} - - -##def mbDonumber(number, modifier=None): -## if not number: -## return -## L = ['{ctrl+numkey%s}'%s for s in str(number)] -## print 'L: %s'% L -## for l in L: -## natut.playString(l, natut.hook_f_systemkeys) - -def mbDonumber(number, modifier=None): - events = [] - if modifier: - events.append (modifiers[modifier][0]) - for n in number: - code = getKeyCode(n) - events.append((natut.wm_keydown, code, 1)) - events.append((natut.wm_keyup, code, 1)) - if modifier: - events.append (modifiers[modifier][1]) - try: - natlink.playEvents(events) - except natlink.NatError: - print("==================") - print("Error playing events in firefox browsing, doNumber: %s"% repr(events)) - - -# standard stuff Joel (adapted for possible empty gramSpec, QH, unimacro) -thisGrammar = ThisGrammar() -if thisGrammar.gramSpec: - thisGrammar.initialize() -else: - thisGrammar = None - -def unload(): - global thisGrammar - if thisGrammar: thisGrammar.unload() - thisGrammar = None diff --git a/src/unimacro/DisabledGrammars/natspeak_sample_docstring.py b/src/unimacro/DisabledGrammars/natspeak_sample_docstring.py deleted file mode 100644 index 1a0e16d..0000000 --- a/src/unimacro/DisabledGrammars/natspeak_sample_docstring.py +++ /dev/null @@ -1,90 +0,0 @@ -# -# Python Macro Language for Dragon NaturallySpeaking -# (c) Copyright 1999 by Joel Gould -# Portions (c) Copyright 1999 by Dragon Systems, Inc. -# -# natspeak_sample_docstring.py -# works only in DragonPad -# -# This is a sample macro file with a few more examples of docstring defined rules. -# start DragonPad and -# try for example: -# sample docstring -# sample chair -# sample this is a test -# -# say show natspeak sample docstring for the complete grammar in .txt format -# say show all grammars (or show grammar sample docstring) for -# presentation of the grammar(s) in an overview window. -# See http://qh.antenna.nl/unimacro (March 2010, Quintijn Hoogenboom) - -import natlink -natut = __import__('natlinkutils') -natqh = __import__('natlinkutilsqh') -natbj = __import__('natlinkutilsbj') -from actions import doKeystroke as keystroke -from actions import doAction as action - -class ThisGrammar(natbj.DocstringGrammar): - """more elaborate example of grammar with docstrings defined rules - """ - def initialize(self): - self.load(self.gramSpec) - self.activateAll() - self.prevHandle = 0 - - def gotBegin(self, moduleInfo): - winHandle = moduleInfo[2] - if self.prevHandle == winHandle: - return - self.prevHandle = winHandle - if natqh.matchModule('natspeak', wantedTitle='dragonpad', - modInfo=moduleInfo): - print('activate grammar %s'% self.name) - self.activateAll() - elif self.isActive(): - print('deactivate grammar %s'% self.name) - self.deactivateAll() - - def gotResultsInit(self, words, fullResults): - keystroke('\n---\nAt start of macro go through gotResultsInit, all words: %s\n'% words) - - def rule_start1(self, words): - """# this is a demo rule (exported): - sample docstring - """ - keystroke('Heard macro "start1" with words: %s\n'% words) - - def rule_start2(self, words): - """ sample - - """ - keystroke('Heard macro "start1" with words: %s\n'% words) - - def subrule_specification(self, words): - """ - # this is a subrule: - table | chair - """ - keystroke(' Heard subrule "specification" with words: %s\n'% words) - - def rule_start3(self, words): - ' sample ' - keystroke('Heard rule "start3" with words: %s\n'% words) - - def importedrule_dgndictation(self, words): - '# imported rule, only comment (docstring may be deleted)' - keystroke(' Heard imported rule "dgndictation" with words: %s\n'% words) - - def gotResults(self, words, fullResults): - keystroke('At end of macro go through gotResults, ' - 'the fullResults were:\n%s\n---\n'% fullResults) - -# standard stuff: -thisGrammar = ThisGrammar() -thisGrammar.initialize() - -def unload(): - global thisGrammar - if thisGrammar: thisGrammar.unload() - thisGrammar = None diff --git a/src/unimacro/DisabledGrammars/winword_styles_unimacro.py b/src/unimacro/DisabledGrammars/winword_styles_unimacro.py deleted file mode 100644 index 6b9a114..0000000 --- a/src/unimacro/DisabledGrammars/winword_styles_unimacro.py +++ /dev/null @@ -1,127 +0,0 @@ -# -# Python Macro Language for Dragon NaturallySpeaking -# (c) Copyright 1999 by Joel Gould -# Portions (c) Copyright 1999 by Dragon Systems, Inc. -# -# This grammar is integrated into unimacro, offering eg show capabilities -# adapted for word styles by Quintijn Hoogenboom (23/10/2008), for comparison with -# Dragonfly example... -# Also see: http://qh.antenna.nl/unimacro/features/grammarclasses/docstringgrammar/examplewordstyles.html -# implemented as DocstringGrammar example (april 2010) -# - -import natlink -natqh = __import__('natlinkutilsqh') -natut = __import__('natlinkutils') -natbj = __import__('natlinkutilsbj') - -import win32api -import win32com.client -consts = win32com.client.constants - -ancestor = natbj.DocstringGrammar -class ThisGrammar(natbj.DocstringGrammar): - - # list is filled in updateStyles, not by the IniGrammar functions: - iniIgnoreGrammarLists = ['style'] - - name = 'word styles' - - # rules in the docstrings of the rules functions below... - #gramSpec = """ - # exported = show styles; - # exported = update styles; - # exported = set style {style}; - #""" - - def initialize(self): - print('init winword_styles_unimacro') - self.load(self.gramSpec) - self.application = None - self.activated = None - self.styles = [] - self.prevInfo = None - - def gotBegin(self,moduleInfo): - if self.prevInfo == moduleInfo: - return - - self.prevInfo = moduleInfo - - winHandle = natut.matchWindow(moduleInfo,'winword','Microsoft Word') - if winHandle: - if self.checkForChanges: - print('word styles (%s), checking the inifile'% self.name) - self.checkInifile() - - if not self.application: - self.application=win32com.client.Dispatch('Word.Application') - if self.activated: - if winHandle != self.activated: - print('DEactivate for previous %s'% self.activated) - self.deactivateAll() - self.activated = None - if not self.activated: - print('activate for %s'% winHandle) - self.activateAll(window=winHandle) - self.activated = winHandle - else: - winHandle = natut.matchWindow(moduleInfo,'winword','') - if not winHandle: - print('other application, release word') - if self.application: - self.application = None - # outside an interesting window so: - return - - # new modInfo, possibly a new document in front: - print('update styles') - self.updateStyles() - - def updateStyles(self): - """update the styles list, either from gotBegin or from a spoken command""" - if self.application: - document = self.application.ActiveDocument - style_map = [(str(s), s) for s in document.Styles] - self.styles = dict(style_map) - self.setList('style', list(self.styles.keys())) - else: - print('no word application loaded... %s'% self.application) - - def rule_updateStyles(self, words): - "update styles" - # possibility to "manually" update the styles list - # not needed in normal use - self.updateStyles() - - def rule_showStyles(self, words): - "show styles" - # print a list of all valid styles in the messages window - if self.styles: - print('styles in use: %s'% list(self.styles.keys())) - else: - print('no styles in use...') - - def rule_setStyle(self, words): - "set style {style}" - #apply a style to the cursor or selection - style = words[-1] - if style in self.styles: - print('setting style %s'% style) - sel = self.application.Selection - sel.Style = style - else: - print('style not in stylelist: %s'% style) - -# standard stuff: -thisGrammar = ThisGrammar() -thisGrammar.initialize() - -def unload(): - global thisGrammar - if thisGrammar: - if thisGrammar.application: - thisGrammar.application = None - thisGrammar.unload() - - thisGrammar = None diff --git a/src/unimacro/UnimacroGrammars/_calculator.py b/src/unimacro/OtherUnimacroGrammars/_calculator.py similarity index 96% rename from src/unimacro/UnimacroGrammars/_calculator.py rename to src/unimacro/OtherUnimacroGrammars/_calculator.py index b309baa..46146f9 100644 --- a/src/unimacro/UnimacroGrammars/_calculator.py +++ b/src/unimacro/OtherUnimacroGrammars/_calculator.py @@ -35,16 +35,17 @@ the grammars _number simple and _number extended. """ import copy -from actions import doKeystroke as keystroke +from dtactions.unimacro.unimacroactions import doAction as action -natut = __import__('natlinkutils') -natqh = __import__('natlinkutilsqh') -natbj = __import__('natlinkutilsbj') +from natlinkcore import natlinkutils as natut +from dtactions.unimacro import unimacroutils +from dtactions.unimacro import unimacroutils +import unimacro.natlinkutilsbj as natbj ancestor = natbj.IniGrammar class ThisGrammar(ancestor): - language = natqh.getLanguage() + language = unimacroutils.getLanguage() normalRules = ['calcnormal', 'cancel'] calcRules = ['calccalc', 'cancel'] # exclusive continueRules = ['calccontinue', 'cancel'] # exclusive @@ -86,10 +87,10 @@ def gotBegin(self, moduleInfo): if self.checkForChanges: self.checkInifile() if self.prevModInfo != moduleInfo: - progInfo = natqh.getProgInfo(modInfo=moduleInfo) + progInfo = unimacroutils.getProgInfo(modInfo=moduleInfo) self.prevModInfo = moduleInfo self.cancelMode() - self.prog = progInfo[0] + self.prog = progInfo.prog if self.prog == 'calc': self.activeSet = None else: @@ -323,6 +324,7 @@ def cancelMode(self): thisGrammar = None def unload(): + #pylint:disable=W0603 global thisGrammar if thisGrammar: thisGrammar.unload() thisGrammar = None @@ -334,4 +336,4 @@ def changeCallback(type,args): if thisGrammar: thisGrammar.cancelMode() - \ No newline at end of file + diff --git a/src/unimacro/UnimacroGrammars/_keystrokes.py b/src/unimacro/OtherUnimacroGrammars/_keystrokes.py similarity index 81% rename from src/unimacro/UnimacroGrammars/_keystrokes.py rename to src/unimacro/OtherUnimacroGrammars/_keystrokes.py index 5d6c2fa..f413fbc 100644 --- a/src/unimacro/UnimacroGrammars/_keystrokes.py +++ b/src/unimacro/OtherUnimacroGrammars/_keystrokes.py @@ -1,4 +1,3 @@ -__version__ = "$Rev: 606 $ on $Date: 2019-04-23 14:30:57 +0200 (di, 23 apr 2019) $ by $Author: quintijn $" # This file is part of a SourceForge project called "unimacro" see # http://unimacro.SourceForge.net and http://qh.antenna.nl/unimacro # (c) copyright 2003 see http://qh.antenna.nl/unimacro/aboutunimacro.html @@ -17,22 +16,20 @@ others continuously. """ -import time -import os +#pylint:disable=R0904, R0913, R0912, C0209 + import sys -import inivars -import types import copy +from dtactions.unimacro import inivars +from dtactions.unimacro.unimacroactions import doKeystroke as keystroke +from dtactions.unimacro.unimacroactions import doAction as action +from dtactions.unimacro import unimacroutils +from unimacro import natlinkutilsbj as natbj +from natlinkcore import nsformat +from natlinkcore import loader import natlink -import nsformat -from actions import doAction as action -from actions import doKeystroke as keystroke - -natut = __import__('natlinkutils') -natqh = __import__('natlinkutilsqh') -natbj = __import__('natlinkutilsbj') - -language = natqh.getLanguage() +natlinkmain = loader.NatlinkMain() +language = unimacroutils.getLanguage() ancestor = natbj.IniGrammar class ThisGrammar(ancestor): @@ -58,13 +55,16 @@ class ThisGrammar(ancestor): exported = "keystrokes (simple|extended)"; """ - def __init__(self): - self.language = natqh.getLanguage() - # here the grammar is not loaded yet, but the ini file is present - self.startInifile() - #print 'requireTimes: %s, simpleOrExtended: %s'% (self.requireTimes, self.doKeystrokesExtended) - self.constructGramSpec(inInit=1) - ancestor.__init__(self) + gramSpec = "# placeholder of gramSpec" + + # def __init__(self, inifile_stem=None): + # self.language = unimacroutils.getLanguage() + # # here the grammar is not loaded yet, but the ini file is present + # self.inifile_stem = inifile_stem + # self.startInifile() + # #print 'requireTimes: %s, simpleOrExtended: %s'% (self.requireTimes, self.doKeystrokesExtended) + # self.constructGramSpec(inInit=1) + # ancestor.__init__(self) def constructGramSpec(self, inInit=0): """return the gramSpec, from gramSpecStart, with several options and tranlation steps @@ -90,15 +90,14 @@ def constructGramSpec(self, inInit=0): #print 'startSpec: %s\n\n'% startSpec startSpec.append(self.lastpartofgramspec) self.gramSpec = copy.copy(startSpec) - if not inInit: - # this should be done only at switchkey command: - self.unload() - self.load(self.gramSpec) - - + # if not inInit: + # # this should be done only at switchkey command: + # self.unload() + # self.load(self.gramSpec) def initialize(self): #print 'self.gramspec: %s'% self.gramSpec + self.constructGramSpec() self.load(self.gramSpec) # call for extra spoken form with difficult numbers # needs self.stripSpokenForm in gotResults... function!!! @@ -113,7 +112,7 @@ def initialize(self): self.resetAllVars() self.resetVars() self.isIgnored = 0 - self.title = 'Unimacro grammar %s (%s) language: %s'% (self.name, __name__, language) + self.title = 'Unimacro grammar {self.name} (__name__) language: {language}' #self.activateAll() self.fillGrammarLists() self.dictateOutputState = -1 # start state for dictate rule (nsformat) @@ -125,11 +124,11 @@ def gotBegin(self, moduleInfo): if self.prevModule == moduleInfo: return - progInfo = natqh.getProgInfo(moduleInfo) + progInfo = unimacroutils.getProgInfo(moduleInfo) self.isIgnored = 0 - if self.ignore and natqh.matchWindow(self.ignore, progInfo=progInfo): + if self.ignore and unimacroutils.matchWindow(self.ignore, progInfo=progInfo): self.isIgnored = 1 return @@ -145,12 +144,12 @@ def gotBegin(self, moduleInfo): ini = self.ini #print 'do keystrokes for mode: %s'% repr(mode) if mode == 'inactive': - print('%s: deactivate: %s'% (self.GetName(), mode)) + print(f'{self.GetName()}: deactivate: {mode}') self.deactivateAll() self.cancelMode() self.resetAllVars() return - elif mode == 'active': + if mode == 'active': repkeySections = ['repkey'] norepkeySections = ['norepkey'] # print 'activate "default mode" keystrokes' @@ -161,9 +160,11 @@ def gotBegin(self, moduleInfo): # self.modeSet is set of modestrings being active: wantExclusive = self.modeSet & self.exclusiveModes # both a set if wantExclusive: - print('make keystokes mode exclusive: %s'% wantExclusive) + print(f'make keystokes mode exclusive: {wantExclusive}') self.setExclusive(1) - #if + # done at start of the grammar, possibly only do it here: + # natlinkmain.set_on_mic_off_callback(self.on_mic_off_callback) + # repkeySections = self.ini.getSectionsWithPrefix('repkey', mode) repkeySections.append('repkey') norepkeySections = self.ini.getSectionsWithPrefix('norepkey', mode) @@ -204,8 +205,8 @@ def gotResults_before(self, words, fullResults): #print '_keystrokes, do a "%s" mouse click'% button if not self.doWaitForMouseToStop(): raise Exception("_keystrokes, mouse did not stop") - natqh.buttonClick(button, nClick) - natqh.visibleWait() + unimacroutils.buttonClick(button, nClick) + unimacroutils.visibleWait() self.hadClick = button def subrule_contextmenu(self, words): @@ -233,7 +234,7 @@ def subrule_contextmenu(self, words): # else: # # def gotResults_dgndictation(self, words, fullResults): - print('words of dgndictation: %s'% words) + print(f'words of dgndictation: {words}') formattedOutput, self.dictateOutputState = nsformat.formatWords(words, state=self.dictateOutputState) self.key = formattedOutput self.flush() @@ -257,12 +258,12 @@ def gotResults_repkey(self, words, fullResults): if self.repkeySections: res = self.ini.get(self.repkeySections, w) else: - print('_keystrokes, no repkeySections for this mode: %s'% repr(self.prevMode)) + print(f'_keystrokes, no repkeySections for this mode: {self.prevMode}') return if res: self.key = res else: - print('rep, found character or something else: %s'% w) + print(f'rep, found character or something else: {w}') posSlash = w.find('\\') if posSlash > 0: self.key = w[:posSlash] @@ -299,11 +300,11 @@ def gotResults_norepkey(self, words, fullResults): if self.repkeySections: res = self.ini.get(self.norepkeySections, w) else: - print('_keystrokes, no norepkeySections for this mode: %s'% self.prevMode) + print(f'_keystrokes, no norepkeySections for this mode: {self.prevMode}') return res = self.ini.get(self.norepkeySections, w) if not res: - raise ValueError("_keystrokes, norepkey: no code found for %s (%s)"% w, (self.fullResults)) + raise ValueError(f'_keystrokes, norepkey: no code found for {w} ({self.fullResults})') self.key = res #print 'norepkey: %s'% self.key self.flush() @@ -345,7 +346,7 @@ def gotResults_click(self, words, fullResults): if not self.doMouseMoveStopClick(): print("you should move the mouse a bit at least!") return - possibleButtons = natqh.joelsButtons + possibleButtons = unimacroutils.joelsButtons possibleClicks = ['1', '2', '3'] clickrules = self.getFromInifile(words[0], 'click') #print 'clickrules: %s'% clickrules @@ -360,20 +361,20 @@ def gotResults_click(self, words, fullResults): if len(parts) > 1: if parts[1] not in possibleClicks: - print('number of clicks (%s) should be one of %s'% (parts[1], possibleClicks)) + print(f'number of clicks ({parts[1]}) should be one of {possibleClicks}') return nClick = int(parts[1]) else: nClick = 1 if len(parts) > 2: - print('currently only (button, clicks) allowed in clickrule, not: %s'% clickrules) + print(f'currently only (button, clicks) allowed in clickrule, not: {clickrules}') return if self.nextRule == 'contextmenu' and nClick == 1: button = 'right' - natqh.buttonClick(button, nClick, modifiers=self.mod) - natqh.visibleWait() + unimacroutils.buttonClick(button, nClick, modifiers=self.mod) + unimacroutils.visibleWait() self.hadClick = button @@ -384,10 +385,10 @@ def doMouseMoveStopClick(self): action("ALERT") if not action("WAITMOUSEMOVE"): action("ALERT 2") - return + return None if not action("WAITMOUSESTOP"): action("ALERT 2") - return + return None action("ALERT") return 1 @@ -413,7 +414,7 @@ def gotResults_startrule(self, words,fullResults): def gotResults_lastkey(self, words,fullResults): self.flush() self.flushAll() - natqh.visibleWait() + unimacroutils.visibleWait() def gotResults(self, words,fullResults): self.flush() @@ -428,15 +429,15 @@ def flush(self): self.hadClick = 0 if self.cap: - self.key = natqh.doCaps(self.key) + self.key = unimacroutils.doCaps(self.key) if self.mod: - self.key = natqh.doModifier(self.key, self.mod) + self.key = unimacroutils.doModifier(self.key, self.mod) if self.count != 1: - self.key = natqh.doCount(self.key, self.count) + self.key = unimacroutils.doCount(self.key, self.count) - if type(self.key) == list: - print('_keystrokes, flush: warning, self.key is list: %s'% self.key) + if isinstance(self.key, list): + print(f'_keystrokes, flush: warning, self.key is list: {self.key}') self.buf.extend(self.key) else: self.buf.append(self.key) @@ -447,12 +448,12 @@ def flushAll(self): try: buf = ''.join(self.buf) except TypeError: - print("---TypeError in flushAll of _keystrokes: %s"% repr(self.buf)) + print(f'---TypeError in flushAll of _keystrokes: {self.buf}') raise #print 'flushAll: %s'% buf if self.codes: - action("SCLIP %s"% buf) + action(f'SCLIP {buf}') elif buf.find("<<") >= 0: action(buf) else: @@ -485,23 +486,23 @@ def gotResults_command(self, words,fullResults): self.cap = 3 def windowPolicy(self, modInfo=None, progInfo=None): - progInfo = progInfo or natqh.getProgInfo(modInfo) + progInfo = progInfo or unimacroutils.getProgInfo(modInfo) #print 'window policy------progInfo: %s'% repr(progInfo) #print 'deactivaterules: %s'% self.deactivateRules #print 'activaterules: %s'% self.activateRules modeSet = [] for mode in self.modes: - if natqh.matchWindow(self.modes[mode], progInfo=progInfo): + if unimacroutils.matchWindow(self.modes[mode], progInfo=progInfo): modeSet.append(mode) self.modeSet = set(modeSet) - if modeSet: return tuple(modeSet) + if modeSet: + return tuple(modeSet) - if natqh.matchWindow(self.activateRules, progInfo=progInfo): - if natqh.matchWindow(self.deactivateRules, progInfo=progInfo): + if unimacroutils.matchWindow(self.activateRules, progInfo=progInfo): + if unimacroutils.matchWindow(self.deactivateRules, progInfo=progInfo): return 'inactive' return 'active' - else: - return 'inactive' + return 'inactive' def showInifile(self, body=None, grammarLists=None, ini=None, @@ -513,24 +514,24 @@ def showInifile(self, body=None, grammarLists=None, ini=None, modesString = ', '.join(self.prevMode) else: modesString = str(self.prevMode) - body.append('current mode/active/inactive: %s'% modesString) + body.append(f'current mode/active/inactive: {modesString}') if not self.prevMode: - body.append("no current mode (yet): %s"% self.prevMode) + body.append(f'no current mode (yet): {self.prevMode}') elif self.prevMode == 'active': pass elif self.prevMode == 'inactive': # probably never comes here, because grammar is inactive at this moment - body.append('inactive in %s'% self.deactivateRules) + body.append(f'inactive in {self.deactivateRules}') else: # give extra moohdes information: body.append('possible modes:') for mode in self.modes: if self.modes[mode] == {mode: None}: - body.append('\t%s: (all windows)'% mode) + body.append(f'\t{mode}: (all windows)') else: - body.append('\t%s: %s'% (mode, self.modes[mode])) + body.append(f'\t{mode}: {self.modes[mode]}') else: - body.append('active/inactive: %s'% self.prevMode) + body.append('active/inactive: {self.prevMode}') if self.doKeystrokesExtended: body.append('do keystrokes extended (with Here and mouse clicking)') @@ -544,7 +545,6 @@ def fillDefaultInifile(self, ini): """initialize as a starting example the ini file obsolete """ - pass def fillInstanceVariables(self): """fills instance variables with data from inifile @@ -586,7 +586,7 @@ def fillInstanceVariables(self): self.exclusiveModes = set(self.ini.getList('general', 'exclusive modes', [])) for m in self.exclusiveModes: if m not in self.modes: - print('warning, exclusive mode "%s" not in defined modes: %s'% (repr(m), list(self.modes.keys()))) + print(f'warning, exclusive mode "{m}" not in defined modes: {self.modes.keys()}') except inivars.IniError: @@ -611,20 +611,27 @@ def cancelMode(self): self.resetAllVars() # standard stuff Joel (adapted for possible empty gramSpec, QH, unimacro) -thisGrammar = ThisGrammar() -if thisGrammar.gramSpec: - thisGrammar.initialize() -else: - thisGrammar = None def unload(): + #pylint:disable=W0603, E0601 global thisGrammar - if thisGrammar: thisGrammar.unload() + if thisGrammar: + thisGrammar.unload() thisGrammar = None -def changeCallback(type,args): - # not active without special version of natlinkmain: - if ((type == 'mic') and (args=='on')): - return # check WAS in natlinkmain... - if thisGrammar: - thisGrammar.cancelMode() + +if __name__ == "__main__": + ## interactive use, for debugging: + natlink.natConnect() + try: + thisGrammar = ThisGrammar(inifile_stem="_keystrokes") + thisGrammar.startInifile() + thisGrammar.initialize() + natlinkmain.set_on_mic_off_callback(thisGrammar.cancelMode) + finally: + natlink.natDisconnect() +elif __name__.find('.') == -1: + # standard startup when Dragon starts: + thisGrammar = ThisGrammar() + thisGrammar.initialize() + natlinkmain.set_on_mic_off_callback(thisGrammar.cancelMode) diff --git a/src/unimacro/UnimacroGrammars/_latex.py b/src/unimacro/OtherUnimacroGrammars/_latex.py similarity index 75% rename from src/unimacro/UnimacroGrammars/_latex.py rename to src/unimacro/OtherUnimacroGrammars/_latex.py index 30f2f9e..c231d19 100644 --- a/src/unimacro/UnimacroGrammars/_latex.py +++ b/src/unimacro/OtherUnimacroGrammars/_latex.py @@ -1,8 +1,7 @@ """Unimacro grammar to Dictate latex markup, as defined in an inifile """ -__version__ = "$Rev: 398 $ on $Date: 2011-03-07 14:50:15 +0100 (ma, 07 mrt 2011) $ by $Author: quintijn $" -# This file is part of a SourceForge project called "unimacro" see +# This file is/was part of a SourceForge project called "unimacro" see # http://unimacro.SourceForge.net and http://qh.antenna.nl/unimacro # (c) copyright 2003 see http://qh.antenna.nl/unimacro/aboutunimacro.html # or the file COPYRIGHT.txt in the natlink\natlink directory @@ -12,16 +11,17 @@ # written by: Frank Olaf Sem-Jacobsen # March 2011 # - +#pylint:disable = R0912, C0209, E1101 import natlink -import nsformat -natqh = __import__('natlinkutilsqh') -natut = __import__('natlinkutils') -natbj = __import__('natlinkutilsbj') -from actions import doAction as action -from actions import doKeystroke as keystroke - -language = natqh.getLanguage() +from natlinkcore import nsformat +from natlinkcore import natlinkstatus +from dtactions.unimacro import unimacroutils +from dtactions.unimacro.unimacroactions import doAction as action +from dtactions.sendkeys import sendkeys as keystroke +import unimacro.natlinkutilsbj as natbj + +status = natlinkstatus.NatlinkStatus() +language = status.language ICAlphabet = natbj.getICAlphabet(language=language) # import re @@ -29,8 +29,6 @@ ancestor = natbj.IniGrammar class ThisGrammar(ancestor): - language = natqh.getLanguage() - name = "latex" gramSpec = """ @@ -45,7 +43,7 @@ class ThisGrammar(ancestor): """ def initialize(self): - if not self.language: + if not language: print("no valid language in grammar "+__name__+" grammar not initialized") return @@ -94,7 +92,7 @@ def gotResults_command(self, words, fullResults): contents = self.get_selection_that(line = 0) if self.hasCommon(words, ['line']): contents = self.get_selection_that(line = 1) - + contents = contents.strip() stringpaste(Cmd) if pos > 0 or self.hasCommon(words, ['arguments']): @@ -112,11 +110,16 @@ def gotResults_command(self, words, fullResults): if label: ## workaround for keystrokes: {{} keystroke('{enter}') - stringpaste(r'\label{}%s}'% (self.makes_label(label, contents))) + stringpaste(r'\label{%s}'% (self.makes_label(label, contents))) keystroke('{enter}') def gotResults_options(self, words, fullResults): selection = self.view_selection_current_line() + if selection: + pass + # print(f'select_current_line: {selection}') + else: + print('no selection found') options = self.getFromInifile(words, 'options', noWarning=1) present = 1 squared = selection.find(']') @@ -133,7 +136,7 @@ def gotResults_options(self, words, fullResults): keystroke('{end}') else: keystroke('{home}') - for i in range(0, squared): + for _ in range(0, squared): keystroke('{right}') if present == 0: keystroke('[') @@ -180,29 +183,30 @@ def gotResults(self, words, fullResults): keystroke('{up}') print('floating: %s'% self.floating) if self.reference: - stringpaste ('\\ref{%s}' % (self.makes_label(self.reference, self.dictation))) + stringpaste('\\ref{%s}' % (self.makes_label(self.reference, self.dictation))) if self.namereference: - stringpaste ('\\nameref{%s}' % (self.makes_label(self.namereference, self.dictation))) + stringpaste('\\nameref{%s}' % (self.makes_label(self.namereference, self.dictation))) if self.label_text: - stringpaste ('\\label{%s}' % (self.makes_label(self.label_text, self.dictation))) + stringpaste('\\label{%s}' % (self.makes_label(self.label_text, self.dictation))) if self.replace_text: - stringpaste (self.dictation) + stringpaste(self.dictation) def gotResults_dgndictation(self, words, fullResults): """do with nsformat functions""" - print('got dgndictation: %s'% words) + # print('got dgndictation: %s'% words) self.dictation, dummy = nsformat.formatWords(words) # state not needed in call - print(' result of nsformat: %s'% repr(self.dictation)) + # print(' result of nsformat: %s'% repr(self.dictation)) def get_selection_that(self, line = 0): - natqh.saveClipboard() + unimacroutils.saveClipboard() if line: action('<><>') else: action('<>') + action('W') contents = natlink.getClipboard().strip().replace('\r', '') if len(contents) == 0: if line: @@ -210,45 +214,64 @@ def get_selection_that(self, line = 0): return "" action('HW select that') action('<>') + action('W') contents = natlink.getClipboard().strip().replace('\r', '') if len(contents) == 0: - print('_latex, empty contents, no last dicatate utterance available') + print('_latex, empty contents, no last dictate utterance available') - natqh.restoreClipboard() + unimacroutils.restoreClipboard() return contents def view_selection_current_line(self): - natqh.saveClipboard() + unimacroutils.saveClipboard() keystroke('{ctrl+c}') + action('W') contents = natlink.getClipboard() if len(contents) == 0: - print('no_space_by_existing selection') + # print('no_space_by_existing selection') keystroke('{end}{shift+home}') keystroke('{ctrl+c}') + action('W') contents = natlink.getClipboard() - natqh.restoreClipboard() + unimacroutils.restoreClipboard() return contents - - def makes_label(self, type, text): - return type + ':' + ''.join(text.split()).lower() + def makes_label(self, Type, Text): + return Type + ':' + ''.join(Text.split()).lower() def stringpaste(t): """paste via clipboard, to circumvent German keyboard issues """ - action('SCLIP "%s"'%t) + print(f'stringpaste: |{t}|') + action(f'SCLIP "{t}"') - - -# standard stuff Joel (QH, Unimacro) -thisGrammar = ThisGrammar() -if thisGrammar.gramSpec: - thisGrammar.initialize() -else: +# standard stuff Joel (QH, Unimacro, python3): +try: + thisGrammar +except NameError: thisGrammar = None def unload(): + #pylint:disable=W0603 global thisGrammar - if thisGrammar: thisGrammar.unload() + if thisGrammar: + thisGrammar.unload() thisGrammar = None + +if __name__ == "__main__": + # here code to interactive run this module + natlink.natConnect() + try: + thisGrammar = ThisGrammar(inifile_stem='_latex') + thisGrammar.startInifile() + thisGrammar.initialize() + Words = ['add', 'option', 'draft'] + FR = {} + thisGrammar.gotResults_options(Words, FR) + finally: + natlink.natDisconnect() +elif __name__.find('.') == -1: + # called from the loader, when starting Dragon/Natlink: + thisGrammar = ThisGrammar() + thisGrammar.initialize() diff --git a/src/unimacro/UnimacroGrammars/_number extended.py b/src/unimacro/OtherUnimacroGrammars/_number extended.py similarity index 88% rename from src/unimacro/UnimacroGrammars/_number extended.py rename to src/unimacro/OtherUnimacroGrammars/_number extended.py index bea8944..9099ea4 100644 --- a/src/unimacro/UnimacroGrammars/_number extended.py +++ b/src/unimacro/OtherUnimacroGrammars/_number extended.py @@ -22,7 +22,7 @@ # # _number.py # written by: Quintijn Hoogenboom (QH softwaretraining & advies) -# August 2003 +# August 2003/November 2022 (python3) # """smart and reliable number dictation @@ -45,22 +45,27 @@ QH050104: standardised things, and put functions in natlinkutilsbj, so that other grammars can invoke the number grammar more easily. """ -from actions import doKeystroke as keystroke -from actions import doAction as action -from actions import getMetaAction +#pylint:disable=C0209, R0904, R0912, R0915 +import natlink +from dtactions.unimacro.unimacroactions import doAction as action +from dtactions.unimacro.unimacroactions import doKeystroke as keystroke +from dtactions.unimacro.unimacroactions import getMetaAction +from dtactions.unimacro import unimacroutils -natut = __import__('natlinkutils') -natqh = __import__('natlinkutilsqh') -natbj = __import__('natlinkutilsbj') -import iban # special module for banknumber (European mainly I think) -import types +import unimacro.natlinkutilsbj as natbj + +from unimacro import iban # special module for banknumber (European mainly I think) # Note: lists number1to99 and number1to9 and n1-9 and n20-90 etc. are taken from function getNumberList in natlinkutilsbj +class NumberException(Exception): + pass + + ancestor = natbj.IniGrammar class ThisGrammar(ancestor): - language = natqh.getLanguage() + language = unimacroutils.getLanguage() #Step 1, choose one of next three grammar rules: # the rule comes from these grammar rules try: @@ -90,29 +95,30 @@ class ThisGrammar(ancestor): except KeyError: print('take number grammar from "enx"') integer999 = natbj.numberGrammarTill999['enx'] - ## 345567;345567 - ## these are special rules for making numbers of specific length. - ## when they appear to be usefull, I will try to make them available in other languages - ## and other cases too: - - amsterdamZuidRule = """ exported = | | ; - = zesentachtig ; - = point (<__thousandslimited> | ); - = {n0-9}{n0-9} | {n10-99}; - = {n0-9}{n0-9}{n0-9} | <__hundredslimited> | {n0-9} ; -<__hundredslimited> = hundred | <__2to9before> hundred | hundred <__1to99after> ; -<__thousandslimited> = thousand | <__2to9before> thousand | thousand <__1to99after> | - <__2to9before> thousand <__1to9after>; - - = <__thousandslimited> | ; - = {n0-9}+ | {n0-9} {n0-9} ; -<__thousands> = duizend | (<__1to99>|<__hundreds>) duizend | duizend (<__1to99>|<__hundreds>) | - (<__1to99>|<__hundreds>) duizend (<__1to99>|<__hundreds>); -<__2to9before> = {n2-9}; -<__1to99after> = {n1-99}; -<__1to9after> = {n1-9}; -""" +# ## 345567;345567 +# ## these are special rules for making numbers of specific length. +# ## when they appear to be useful, I will try to make them available in other languages +# ## and other cases too: +# +# amsterdamZuidRule = """ exported = | | ; +# = zesentachtig ; +# = point (<__thousandslimited> | ); +# = {n0-9}{n0-9} | {n10-99}; +# = {n0-9}{n0-9}{n0-9} | <__hundredslimited> | {n0-9} ; +# <__hundredslimited> = hundred | <__2to9before> hundred | hundred <__1to99after> ; +# <__thousandslimited> = thousand | <__2to9before> thousand | thousand <__1to99after> | +# <__2to9before> thousand <__1to9after>; +# +# = <__thousandslimited> | ; +# = {n0-9}+ | {n0-9} {n0-9} ; +# <__thousands> = duizend | (<__1to99>|<__hundreds>) duizend | duizend (<__1to99>|<__hundreds>) | +# (<__1to99>|<__hundreds>) duizend (<__1to99>|<__hundreds>); +# <__2to9before> = {n2-9}; +# <__1to99after> = {n1-99}; +# <__1to9after> = {n1-9}; +# +# """ ##8600 8650 86 2008 def gotResults___hundredslimited(self,words,fullResults): @@ -240,20 +246,10 @@ def gotResults___2to9before(self, words, fullResults): #failed to get this working: # exported = (Tuple|List|Argument) (Number | (Variable|String) | None)+; - def __init__(self): - """start the inifile and add to grammar if needed a special rule - """ - self.startInifile() - #print 'enableSearchCommands: %s'% self.enableSearchCommands - if self.specialAmsterdamZuid: - self.gramSpec.append(self.amsterdamZuidRule) - ancestor.__init__(self) - - def gotBegin(self,moduleInfo): if self.checkForChanges: self.checkInifile() - self.progInfo = natqh.getProgInfo(moduleInfo) + self.progInfo = unimacroutils.getProgInfo(moduleInfo) def initialize(self): if not self.language: @@ -299,7 +295,6 @@ def gotResults_testnumber1(self, words, fullResults): # because more numbers can be collected, the previous ones be collected first # if you expect only one number, this function can be skipped (but it is safe to call): self.collectNumber() - result = self.hasCommon(words, 'number') if self.hasCommon(words, 'number'): if self.number: # flush previous number @@ -320,7 +315,7 @@ def gotResults_testnumber2(self, words, fullResults): elif self.hasCommon(words, 'through'): self.waitForNumber('through') else: - raise NumberError('invalid user input in grammar %s: %s'%(__name__, words)) + raise NumberException('invalid user input in grammar %s: %s'%(__name__, words)) def gotResults_spacingnumber(self, words, fullResults): self.collectNumber() @@ -346,7 +341,7 @@ def gotResults_pagenumber(self, words, fullResults): elif self.hasCommon(words, 'through'): self.waitForNumber('through') else: - raise NumberError('invalid words in pagenumber rule in grammar %s: %s'%(__name__, words)) + raise NumberException('invalid words in pagenumber rule in grammar %s: %s'%(__name__, words)) def gotResults_filenamelastpage(self, words, fullResults): # additional command, compose filename with the last called page number(s). @@ -463,7 +458,7 @@ def gotResults(self, words, fullResults): isTop = (self.progInfo[2] == 'top') ma = getMetaAction('pagestart', progInfo=self.progInfo) if not ma: - print('no metaactions defined for pagestart, stop command %s'% self.progInfo[0]) + print('no metaactions defined for pagestart, stop command %s'% self.progInfo.prog) if isTop: if self.through: keystroke(" page %s-%s"% (self.page, self.through)) @@ -475,7 +470,7 @@ def gotResults(self, words, fullResults): action("<>") keystroke(self.page) - if self.progInfo[0] == 'pdf24-creator' and self.through == '': + if self.progInfo.prog == 'pdf24-creator' and self.through == '': self.through = self.page if self.through: @@ -485,7 +480,7 @@ def gotResults(self, words, fullResults): action("<>") return # page command - elif self.pair: + if self.pair: self.pair = self.doMinus('pair', 'minus') print("(%s, %s) "% (self.number, self.pair)) @@ -515,7 +510,7 @@ def gotResults(self, words, fullResults): elif self.ibanCheck and self.ibanHeader: try: # print 'ibanheader: %s, number: %s'% (self.ibanHeader, self.number) - result = Iban = iban.create_iban(self.ibanHeader[:2], self.ibanHeader[2:], self.number) + result = iban.create_iban(self.ibanHeader[:2], self.ibanHeader[2:], self.number) except iban.IBANError as err: print('invalid iban %s, %s (%s)'% (self.ibanHeader, self.number, err)) return @@ -535,7 +530,7 @@ def outputNumber(self, number): number = str(number) keystroke(number) - prog = natqh.getProgName() + prog = unimacroutils.getProgName() if prog in ['iexplore', 'firefox', 'chrome', 'safari']: keystroke('{tab}') elif prog in ['natspeak']: @@ -567,13 +562,24 @@ def doMinus(self, number, minus): return Nstring # standard stuff Joel (adapted for possible empty gramSpec, QH, unimacro) -thisGrammar = ThisGrammar() -if thisGrammar.gramSpec: - thisGrammar.initialize() -else: - thisGrammar = None - def unload(): + #pylint:disable=W0603 global thisGrammar - if thisGrammar: thisGrammar.unload() - thisGrammar = None \ No newline at end of file + if thisGrammar: + thisGrammar.unload() + thisGrammar = None + +if __name__ == "__main__": + ## interactive use, for debugging: + natlink.natConnect() + try: + thisGrammar = ThisGrammar(inifile_stem="_number extended") + thisGrammar.startInifile() + thisGrammar.initialize() + finally: + natlink.natDisconnect() +elif __name__.find('.') == -1: + # standard startup when Dragon starts: + thisGrammar = ThisGrammar() + thisGrammar.initialize() + diff --git a/src/unimacro/UnimacroGrammars/_oops.py b/src/unimacro/OtherUnimacroGrammars/_oops.py similarity index 72% rename from src/unimacro/UnimacroGrammars/_oops.py rename to src/unimacro/OtherUnimacroGrammars/_oops.py index 63abdd1..08a799a 100644 --- a/src/unimacro/UnimacroGrammars/_oops.py +++ b/src/unimacro/OtherUnimacroGrammars/_oops.py @@ -50,35 +50,42 @@ """ +#pylint:disable=R0912, R0914, R0915 +#pylint:disable=E1101 -import natlink -import win32gui -import utilsqh -natut = __import__('natlinkutils') -natqh = __import__('natlinkutilsqh') -natbj = __import__('natlinkutilsbj') import time -import copy -import sys import os -import operator +from pathlib import Path + +import natlink +from natlinkcore import natlinkstatus +from natlinkcore import loader +from dtactions.unimacro import unimacroutils +import unimacro.natlinkutilsbj as natbj + logHour = -1 logFile = '' -language = natqh.getLanguage() -version = natqh.getDNSVersion() -UUDirectory = natqh.getUnimacroUserDirectory() +status = natlinkstatus.NatlinkStatus() +natlinkmain = loader.NatlinkMain() + +language = status.language +version = status.getDNSVersion() +UDDirectory = status.getUnimacroDataDirectory() # print 'language: %s (%s)'% (language, type(language)) # print 'version: %s (%s)'% (version, type(version)) # print 'getUnimacroUserDirectory: %s (%s)'% (UUDirectory, type(UUDirectory)) -logFolder = os.path.join(UUDirectory, language + "_log", natqh.getUser()) -print('_oops, logfolder: %s'% logFolder) +logFolder = Path(UDDirectory)/f'{status.language}_log'/status.user def getLogFileName(): """get name with date and time, record hour in logHour""" + #pylint:disable=W0603 global logHour, logFile - utilsqh.createFolderIfNotExistent(logFolder) + if not logFolder.exists(): + print(f'Want to create log folder: {logFolder}') + if not logFolder.exists(): + logFolder.mkdir(parents=True) lTime = time.localtime() logFile = time.strftime("%Y-%m-%d %H%M", lTime) + '.txt' logHour = lTime[3] @@ -88,7 +95,7 @@ def getLogFileName(): ChooseList = ['1','2','3','4','5','6','7','8','9','10'] # get language for different language versions: -language = natqh.getLanguage() +language = unimacroutils.getLanguage() # Number of times the correction is executed when choosing weak # (default), middle or strong @@ -102,23 +109,23 @@ def getLogFileName(): # FORMATS and FormatComments MUST MATCH! FORMATS = { # for letters in advance of a variable: - 1: ( natqh.wf_TurnCapitalizationModeOn | - natqh.wf_TurnOffSpacingBetweenWords | - natqh.wf_DoNotApplyFormattingToThisWord + 1: ( unimacroutils.wf_TurnCapitalizationModeOn | + unimacroutils.wf_TurnOffSpacingBetweenWords | + unimacroutils.wf_DoNotApplyFormattingToThisWord ), # for continuing after a variable: - 2: ( natqh.wf_RestoreNormalCapitalization | - natqh.wf_RestoreNormalSpacing + 2: ( unimacroutils.wf_RestoreNormalCapitalization | + unimacroutils.wf_RestoreNormalSpacing ), # for continuing after a variable + extra space: - 3: ( natqh.wf_RestoreNormalCapitalization | - natqh.wf_RestoreNormalSpacing | - natqh.wf_AddAnExtraSpaceFollowingThisWord + 3: ( unimacroutils.wf_RestoreNormalCapitalization | + unimacroutils.wf_RestoreNormalSpacing | + unimacroutils.wf_AddAnExtraSpaceFollowingThisWord ), # for continuing after a variable, no space before: - 4: ( natqh.wf_RestoreNormalCapitalization | - natqh.wf_RestoreNormalSpacing | - natqh.wf_NoSpacePreceedingThisWord + 4: ( unimacroutils.wf_RestoreNormalCapitalization | + unimacroutils.wf_RestoreNormalSpacing | + unimacroutils.wf_NoSpacePreceedingThisWord ) } @@ -129,10 +136,7 @@ def getLogFileName(): 3: 'herstel + spatie (als "spatie")', 4: 'herstel + geen spatie ervoor (als ":")' } - if natqh.getDNSVersion() >= 7: - ScratchThatCommand = ['schrap', 'dat'] - else: - ScratchThatCommand = ['Schrap', 'dat'] + ScratchThatCommand = ['schrap', 'dat'] WordCommand = 'commando' WordDictate = 'dictaat' else: @@ -142,10 +146,7 @@ def getLogFileName(): 3: 'restore and add a space (like "space-bar")', 4: 'restore, but no space before (like ":")' } - if natqh.getDNSVersion() >= 7: - ScratchThatCommand = ['scratch', 'that'] - else: - ScratchThatCommand = ['Scratch', 'That'] + ScratchThatCommand = ['scratch', 'that'] WordCommand = 'commando' WordDictate = 'dictate' @@ -155,34 +156,40 @@ def getLogFileName(): else: DoFormatting = 1 +thisGrammar = None ancestor = natbj.IniGrammar class ThisGrammar(ancestor): iniIgnoreGrammarLists = ['chooselist'] # are set in this module name = "oops" gramSpec = """ exported = Oops; +# standard stuff Joel (adapted for possible empty gramSpec, QH, unimacro) + exported = Cancel | OK | ; = (Choose|Format|Delete|Properties) {chooselist} | (Choose|Format|Delete|Properties) {chooselist}(Weak|Medium|Strong); exported = Cancel | OK | (Choose Format (1 | 2 | 3| 4)); """ def initialize(self): - self.load(self.gramSpec, allResults=1) + # load if ini file gives permission: + self.switchOnOrOff(activateRule='oops', allResults=1) + if not self.isLoaded(): + # print(f'{self.name}: grammar is not loaded') + return self.oopsFlag = 0 self.lastResObj = None self.messageHndle = 0 self.setList('chooselist', ChooseList) - if language == 'nld': - print('Grammatica _oops ge-initialiseerd') - else: - print('Grammar _oops initialized') + # if language == 'nld': + # print('Grammatica _oops ge-initialiseerd') + # else: + # print('Grammar _oops initialized') self.cancelMode() self.prevModinfo = None - self.switchOnOrOff(activateRule='oops') if self.logging: - print('_oops, logging of utterances to dir:\n\t%s'% logFolder) + print(f'{self.name}: logging of utterances to dir:\n\t{logFolder}') else: - print('_oops, NO logging of utterances') + print('{self.name}, NO logging of utterances') def fillInstanceVariables(self): """fills the necessary instance variables @@ -203,10 +210,13 @@ def gotBegin(self,moduleInfo): if logHour != lTime[3]: #print 'get new logfilename' getLogFileName() - prog = os.path.split(moduleInfo[0])[1] + self.progInfo = unimacroutils.getProgInfo(modInfo=moduleInfo) + prog = self.progInfo.prog + hndle = self.progInfo.hndle + title = self.progInfo.title minutes = time.strftime("%H:%M", time.localtime()) - logToFile('\n%s---%s---%s(%s)'% (minutes, prog, moduleInfo[1], moduleInfo[2])) + logToFile(f'\n{minutes}---{prog}---{title}({hndle})') self.prevModinfo = moduleInfo #else: # print 'no logging or same moduleInfo: %s, %s, %s'% (self.logging, repr(self.prevModinfo), repr(moduleInfo)) @@ -230,7 +240,7 @@ def gotResultsObject(self,recogType,resObj): try: words = resObj.getWords(0) except (natlink.OutOfRange, IndexError): - words = "" + words = "" resCode = -1 isDictate = -1 @@ -238,10 +248,12 @@ def gotResultsObject(self,recogType,resObj): for i in range(10): try: res = resObj.getResults(i) - try: - lenWave = len(resObj.getWave()) - except natlink.DataMissing: - lenWave = 0 + ##TODO DOUG + # try: + # lenWave = len(resObj.getWave()) + # except natlink.DataMissing: + # lenWave = 0 + lenWave = 0 k,rest = int(lenWave/1000), lenWave%1000 resCode = res[0][1] resCode = resCode & 0x7fffffff @@ -255,17 +267,17 @@ def gotResultsObject(self,recogType,resObj): if isDictate == -1: line = ' ' elif isDictate and not resCode: - line = ' %s (only dictate alternatives)'% ' '.join(words) + line = f' {" ".join(words)} (only dictate alternatives)' elif isDictate: - line = ' %s (dictate, command alternatives)' % ' '.join(words) + line = f' {" ".join(words)} (dictate, command alternatives)' else: - line = ' %s (command %s)'% (words, resCode) + line = f' {words} (command {resCode})' if k == -1: logToFile(line+'(nowave)') elif rest <= 500: - logToFile(line+'(%sk+%s)'% (k, rest)) + logToFile(line+f'({k}k+{rest})') else: - logToFile(line+'(%sk-%s)'% (k+1, 1000-rest)) + logToFile(line+'({k+1}k-{1000-rest})') if recogType == 'other': @@ -280,16 +292,16 @@ def gotResults_oops(self,words,fullResults): ## t0 = time.time() ## try:fellow,hellohellohellohello hellohello,fellow hello hello hello ## try: -## natqh.SetForegroundWindow(self.messageHndle) +## unimacroutils.SetForegroundWindow(self.messageHndle) ## except: - natqh.switchToWindowWithTitle("Messages from Python Macros") + unimacroutils.switchToWindowWithTitle("Messages from Python Macros") ## self.messageHndle = natlink.getCurrentModule()[2] ## print 'new handle for message window: %s'% self.messageHndle ## print 'time to switch:', time.time() - t0 if not self.lastResObj: print('no object to Oops') - natqh.Wait(0.1) - natqh.returnFromMessagesWindow() + unimacroutils.Wait(0.1) + unimacroutils.returnFromMessagesWindow() return # Go through the alternatives in the results object SingleWord = 0 # so formatting can be done @@ -307,9 +319,9 @@ def gotResults_oops(self,words,fullResults): ## if wordInfo: ## pron = map(lambda x: x[6].join(wordInfo)) if resCode: - print("%s:\t[%s] (%s %s)" % (i+1, repr(words), WordCommand,resCode)) + print(f'{i+1}:\t[{words}] ({WordCommand} {resCode})') else: - print("%s:\t%s (%s)" % (i+1, repr(words), WordDictate)) + print(f'{i+1}:\t{words} ({WordDictate})') if i == 0: self.FirstIsDictate = 1 if len(words) == 1: @@ -321,34 +333,34 @@ def gotResults_oops(self,words,fullResults): else: i = 10 if language == 'nld': - print("OK, Annuleren, of Kies 1, ..., Kies %s [middel|sterk]" % i) + print(f'OK, Annuleren, of Kies 1, ..., Kies {i} [middel|sterk]') if SingleWord: - print("of Format #, Verwijder # of Eigenschappen # (# = 1, ..., %s)" % i) + print(f'of Format #, Verwijder # of Eigenschappen # (# = 1, ..., {i}') else: - print("OK, Cancel, or Choose 1, ..., Choose %s [Medium|Strong]" % i) + print(f'OK, Cancel, or Choose 1, ..., Choose {i} [Medium|Strong]') if SingleWord: - print("or Format #, Delete # or Properties # (# = 1, ..., %s)" %i) + print(f'or Format #, Delete # or Properties # (# = 1, ..., {i})') self.oopsFlag = 3 self.activateSet(['inoops'],exclusive=1) self.setList('chooselist', ChooseList[:i]) - natqh.switchToWindowWithTitle("Messages from Python Macros") + unimacroutils.switchToWindowWithTitle("Messages from Python Macros") def gotResults_inoops(self,words,fullResults): - nCorr = choiceWeak - choice = 0 + # nCorr = choiceWeak + # choice = 0 if not self.lastResObj: self.cancelMode() - natqh.returnFromMessagesWindow() + unimacroutils.returnFromMessagesWindow() if self.hasCommon(words, 'Cancel'): texts = dict(nld='oeps geannuleerd') t = texts.get(self.language, 'oops canceled') self.DisplayMessage(t) print('cancelling exclusive oops mode') - natqh.Wait() + unimacroutils.Wait() self.cancelMode() - natqh.returnFromMessagesWindow() + unimacroutils.returnFromMessagesWindow() return choice = 0 if self.hasCommon(words, 'OK'): @@ -374,15 +386,15 @@ def gotResults_choose(self, words, fullResults): choice = int(words[-1]) if not choice: print('no valid choice given') - natqh.Wait(0.2) + unimacroutils.Wait(0.2) self.cancelMode() - natqh.returnFromMessagesWindow() + unimacroutils.returnFromMessagesWindow() return try: newWords = self.lastResObj.getWords(choice-1) except natlink.OutOfRange: i = choice-1 - print('_oops, choose %s, no result number %s'% (i,i)) + print(f'_oops, choose {i}, no result number {i}') return res = self.lastResObj.getResults(choice-1) resCode = res[0][1] @@ -410,17 +422,17 @@ def gotResults_choose(self, words, fullResults): return numChoices = len(fKeys) if language == 'nld': - print('Formatteren van: %s'% self.newWord) - print('Kies Format 1, ..., %i of zeg "Annuleren"' %numChoices) + print(f'Formatteren van: {self.newWord}') + print(f'Kies Format 1, ..., {numChoices} of zeg "Annuleren"') elif language == 'enx': - print('Formating: %s'% self.newWord) - print('Choose Format 1, ..., %i, or say "Cancel"' % numChoices) + print(f'Formating: {self.newWord}') + print(f'Choose Format 1, ..., {numChoices}, or say "Cancel"') else: print('invalid language, skip this') self.cancelMode() return for n in range(numChoices): - print('%s:\t%s'%(n+1, FormatComments[n+1])) + print(f'{n+1}:\t{FormatComments[n+1]}') # Entered the new exclusive grammar rules, for the right # format to be chosen @@ -437,7 +449,7 @@ def gotResults_choose(self, words, fullResults): time.sleep(1.5) else: natlink.deleteWord(newWords[0]) - print('deleted: %s' % newWords[0]) + print(f'deleted: {newWords[0]}') elif self.hasCommon(words, ['Properties','Eigenschappen']): if resCode: print('no properties on a command!') @@ -448,66 +460,62 @@ def gotResults_choose(self, words, fullResults): else: self.newWord = newWords[0] props = natlink.getWordInfo(self.newWord) - print('properties of %s: %x' % (self.newWord, props)) - p = natqh.ListOfProperties(props) + print(f'properties of {self.newWord}: {props}') + p = unimacroutils.ListOfProperties(props) if p: for pp in p: print(pp) time.sleep(4.0) elif self.hasCommon(words, ['Choose', 'Kies', 'OK']): hadChoose = 1 - print('correcting: %s (%s times)'%(newWords,self.nChoice)) + print(f'correcting: {newWords} ({self.nChoice})') for i in range(self.nChoice): result = self.lastResObj.correction(newWords) if not result: print('correction failed') break else: - print('corrected %s times'% self.nChoice) + print(f'corrected {self.nChoice} times') else: - print('invalid word in command: %s' % repr(words)) + print(f'invalid word in command: {words}') time.sleep(2.0) time.sleep(1.0) self.cancelMode() - natqh.returnFromMessagesWindow() + unimacroutils.returnFromMessagesWindow() # Like in DragonDictate, when the word was not a command but a # dictate word, the last phrase is scratched and replaced by the new # text or the new command. if hadChoose and self.FirstIsDictate: - print('mimic first: %s'% ScratchThatCommand) natlink.recognitionMimic(ScratchThatCommand) - print('now mimic: %s'% newWords) natlink.recognitionMimic(newWords) def gotResults_inoops2(self,words,fullResults): if self.lastResObj: fstring = '' if self.hasCommon(words, 'Cancel'): - natqh.Wait() + unimacroutils.Wait() self.cancelMode() - natqh.returnFromMessagesWindow() + unimacroutils.returnFromMessagesWindow() return try: fNum = int(words[-1]) - except ValuerError: + except ValueError: fNum = '' - # fNum = int(words[-1]) - if fNum in list(FORMATS.keys()): - fstring = FORMATS[fNum] - else: - print('invalid paramter choosen: %s' % repr(words)) - fstring = '' + + fstring = FORMATS.get(fNum, '') + if fstring and self.newWord: oldFormat = natlink.getWordInfo(self.newWord) if fstring == oldFormat: - print('format of %s is already: %x' % (self.newWord, fstring)) + print(f'format of {self.newWord} is already: {fstring}') else: - print('formatting word: %s from hex %x to hex: %x'%(self.newWord, oldFormat, fstring)) + ##TODO QH + print(f'formatting word: {self.newWord} from hex {oldFormat:x} to hex: {fstring} (cannot format string to hex)'%(self.newWord, oldFormat, fstring)) natlink.setWordInfo(self.newWord, fstring) self.newWord = "" time.sleep(1.0) self.cancelMode() - natqh.returnFromMessagesWindow() + unimacroutils.returnFromMessagesWindow() def cancelMode(self): #print "end of oops exclusive mode", also called when microphone is toggled. @@ -518,13 +526,6 @@ def cancelMode(self): self.activateSet(['oops'], exclusive = 0) self.newWord = '' -# standard stuff Joel (adapted for possible empty gramSpec, QH, unimacro) -thisGrammar = ThisGrammar() -if thisGrammar.gramSpec: - thisGrammar.initialize() -else: - thisGrammar = None - def logToFile(line): """logging ! """ @@ -533,22 +534,29 @@ def logToFile(line): if not logFile: print('_oops, logging: cannot find valid name for logFile') return - sock = open(logFile, 'a') - if not line.endswith('\n'): - line += '\n' - sock.write(line) - sock.close() - -def changeCallback(type,args): - # not active without special version of natlinkmain: - if ((type == 'mic') and (args=='on')): - return # check WAS in natlinkmain... - if thisGrammar: - thisGrammar.cancelMode() + with open(logFile, 'a', encoding='utf8') as fp: + if not line.endswith('\n'): + line += '\n' + fp.write(line) +# standard stuff Joel (adapted for possible empty gramSpec, QH, unimacro) def unload(): + #pylint:disable=W0603 global thisGrammar if thisGrammar: thisGrammar.unload() thisGrammar = None +if __name__ == "__main__": + ## interactive use, for debugging: + natlink.natConnect() + try: + thisGrammar = ThisGrammar() + thisGrammar.initialize() + finally: + natlink.natDisconnect() +elif __name__.find('.') == -1: + # standard startup when Dragon starts: + thisGrammar = ThisGrammar() + thisGrammar.initialize() + natlinkmain.set_on_mic_off_callback(thisGrammar.cancelMode) diff --git a/src/unimacro/UnimacroGrammars/_repeat.py b/src/unimacro/OtherUnimacroGrammars/_repeat.py similarity index 83% rename from src/unimacro/UnimacroGrammars/_repeat.py rename to src/unimacro/OtherUnimacroGrammars/_repeat.py index 6c2e03a..9a56bba 100644 --- a/src/unimacro/UnimacroGrammars/_repeat.py +++ b/src/unimacro/OtherUnimacroGrammars/_repeat.py @@ -35,23 +35,21 @@ -added continuous search """ - +#pylint:disable=R0904, E1101, R0912, R0915, C0321 # -natqh = __import__('natlinkutilsqh') -natbj = __import__('natlinkutilsbj') -natut = __import__('natlinkutils') -from actions import doAction as action - +import time import os import os.path -import sys -import time # for clock +from dtactions.sendkeys import sendkeys +from dtactions.unimacro import unimacroutils +# from dtactions.unimacro.unimacroactions import doAction as action +import unimacro.natlinkutilsbj as natbj +from natlinkcore import natlinkutils +from natlinkcore import natlinktimer +from natlinkcore import natlinkstatus import natlink -import natlinktimer -import types - -DEBUG = 0 - +DEBUG = 1 +status = natlinkstatus.NatlinkStatus() stateError = 'invalid state for timer routine' # For caret movement, this represents the default speed in milliseconds @@ -75,16 +73,16 @@ for state in states: if state in defaultSpeed: - d = defaultSpeed[state] - if len(d) == 2: - rate = (d[1]/d[0])**0.25 + ds = defaultSpeed[state] + if len(ds) == 2: + rate = (ds[1]/ds[0])**0.25 - SPEED[state] = (d[0], int(d[0]*rate), int(d[0]*rate*rate), - int(d[0]*rate*rate*rate), d[1]) - elif len(d) == 5: + SPEED[state] = (ds[0], int(ds[0]*rate), int(ds[0]*rate*rate), + int(ds[0]*rate*rate*rate), ds[1]) + elif len(ds) == 5: SPEED[state] = defaultSpeed[state][:] else: - print('no valid speeds for: %s'% state) + print(f'no valid speeds for: {state}') defaultMousePixels = 1 waitingSpeed = 500 @@ -105,7 +103,7 @@ # in "hold on" showAll = 1 -language = natqh.getLanguage() +language = unimacroutils.getLanguage() normalSet = ['startMoving', 'startMousing', 'startRepeating', 'startSearching'] ############################################################################ # @@ -233,7 +231,7 @@ def unload(self): """ def initialize(self): - debugPrint('init language: %s' % language) + debugPrint(f'init language: {language}') self.load(self.gramSpec, allResults = 1) self.activateSet(normalSet, exclusive=0) #self.setList('count', Counts) @@ -268,9 +266,9 @@ def cancelMode(self): debugPrint('switch of dragging') xPos,yPos = natlink.getCursorPos() if self.drag == 2: - natlink.playEvents([(natut.wm_rbuttonup,xPos,yPos)]) + natlink.playEvents([(natlinkutils.wm_rbuttonup,xPos,yPos)]) else: - natlink.playEvents([(natut.wm_lbuttonup,xPos,yPos)]) + natlink.playEvents([(natlinkutils.wm_lbuttonup,xPos,yPos)]) self.drag = 0 elif self.state == 'searching': self.stopSearch() @@ -288,10 +286,9 @@ def cancelMode(self): self.hadRepeat = 0 self.repeatStuff = None self.lastResults = [] + print('_repeat, return to normal state, non exclusive') self.activateSet(normalSet, exclusive=0) - resetExclusiveMode = cancelMode - ## def waitMode(self): ## if self.waiting: ## debugPrint('in timer, already waiting') @@ -309,18 +306,15 @@ def cancelMode(self): def onTimer(self): ## if self.lastClock: ## diff = int((time.clock() - self.lastClock) * 1000 ) - if natbj.IsDisplayingMessage: - debugPrint('in timer, displaying message, returning') - return moduleInfo = natlink.getCurrentModule() if natlink.getMicState() == 'on' and moduleInfo[2] == self.moduleInfo[2]: if self.inside or self.insideCommand: self.setTrayIcon(1) return - elif self.waiting: + if self.waiting: self.setTrayIcon(1) return - elif self.doAction(): + if self.doAction(): return # this is the only good exit from onTimer!!!! self.cancelMode() @@ -329,29 +323,29 @@ def startNow(self): k = self.state + self.minorState s = self.curSpeed + 2 # very slow =2 -->> 0 if self.waiting: - natlinktimer.setTimerCallback(self.onTimer, waitingSpeed) + natlinktimer.setTimerCallback(self.onTimer, waitingSpeed, callAtMicOff=self.cancelMode) elif k == 'mousing' or self.state == 'dragging': speed = SPEED[k][s] steps = defaultMousePixels - print('mousing/dragging, speed: %s, steps: %s'% (speed, steps)) + print(f'mousing/dragging, speed: {speed}, steps: {steps}') if s < minSpeed: steps = (minSpeed//speed) + 1 speed = steps*speed if steps < defaultMousePixels: steps = defaultMousePixels speed = speed*defaultMousePixels/steps - print('enlarge steps: %s, new speed: %s'% (steps, speed)) + print(f'enlarge steps: {steps}, new speed: {speed}') else: speed = s - debugPrint('mouse starting with speed: %s, steps: %s'% (speed, steps)) - natlinktimer.setTimerCallback(self.onTimer, speed) + debugPrint(f'mouse starting with speed: {speed}, steps: {steps}') + natlinktimer.setTimerCallback(self.onTimer, speed, callAtMicOff=self.cancelMode) self.mouseSteps = steps elif k in SPEED: - debugPrint('starting with speed: %s'% SPEED[k][s]) - natlinktimer.setTimerCallback(self.onTimer, SPEED[k][s], debug=1) + debugPrint(f'starting with speed: {SPEED[k][s]}') + natlinktimer.setTimerCallback(self.onTimer, SPEED[k][s], callAtMicOff=self.cancelMode) else: - debugPrint("timer starting with unknown speed for state/minorstate: %s"%k) - natlinktimer.setTimerCallback(self.onTimer, defaultSpeed) + debugPrint(f'timer starting with unknown speed for state/minorstate: {k}') + natlinktimer.setTimerCallback(self.onTimer, defaultSpeed, callAtMicOff=self.cancelMode) self.inTimer = 1 @@ -361,7 +355,7 @@ def doAction(self): if self.state in ['moving', 'selecting','searching']: if not self.curDir: debugPrint('do action, no direction specified') - return + return None key = 'ext' + self.curDir if self.minorState == 'page': if self.curDir == 'down': @@ -369,7 +363,7 @@ def doAction(self): elif self.curDir == 'up': key = 'extpgup' else: - debugPrint('invalid direction for minorState page: %s' % self.curDir) + debugPrint('invalid direction for minorState page: {self.curDir}') elif self.minorState in ['word', 'paragraph'] : key = 'ctrl+' + key @@ -386,33 +380,33 @@ def doAction(self): elif self.curDir == 'left': keyBefore = 'ctrl+extpgdn' elif self.curDir == 'right': keyBefore = 'ctrl+extpgup' else: - debugPrint('invalid direction in scrollcommand: %s'% self.curDir) + debugPrint(f'invalid direction in scrollcommand: {self.curDir}') if keyBefore: - natut.playString("{"+keyBefore+"}") + sendkeys("{"+keyBefore+"}") self.startScroll = 0 self.setTrayIcon(1) - natut.playString("{"+key+nowCount+"}") + sendkeys("{"+key+nowCount+"}") elif self.state == 'selecting': self.setTrayIcon(1) - natut.playString("{shift+"+key+nowCount+"}") + sendkeys("{shift+"+key+nowCount+"}") elif self.state == 'repeating': self.setTrayIcon(1) self.repeatNow() elif self.state == 'searching': self.setTrayIcon(1) if not self.curDir: - print('searching, no current direction: %s, assume down'% self.curDir) + print(f'searching, no current direction: {self.curDir}, assume down') self.curDir = self.getLastSearchDirection() or 'down' self.insideCommand = 1 count = self.Count or 1 - for i in range(count): + for _ in range(count): res = self.searchForText(self.curDir) self.curDir = self.getLastSearchDirection() if res == -2: # missing search, did cancel mode - return - natqh.visibleWait() + return None + unimacroutils.visibleWait() self.insideCommand = 0 elif self.state == 'mousing': self.setTrayIcon(1) @@ -427,23 +421,16 @@ def doAction(self): else: self.moveMouse(self.curDir, self.mouseSteps) else: - return + return None self.lastClock = time.time() return 1 # good exit def gotBegin(self,moduleInfo): - if natbj.IsDisplayingMessage: - debugPrint('displaying message, ignoring generic movement') - return if self.inTimer: self.inside = 1 def gotResultsObject(self,recogType,resObj): - if natbj.IsDisplayingMessage: - debugPrint('displaying message, ignoring generic movement') - return - if recogType == 'reject': return handle = natlink.getCurrentModule()[2] @@ -469,7 +456,7 @@ def gotResultsObject(self,recogType,resObj): self.lastResults = self.lastResults[1:] #debugPrint('lastResults: %s' % `self.lastResults`) else: - debugPrint('callbackdepth %s, words: %s'%(natlink.getCallbackDepth(), words)) + debugPrint(f'callbackdepth {natlink.getCallbackDepth()}, words: {words}') self.inside = 0 return ## skipped this, because it interferes with _message: @@ -477,21 +464,21 @@ def gotResultsObject(self,recogType,resObj): ## if self.inTimer and self.missed: ## self.doAction() ## self.startNow() - elif recogType == 'self': + if recogType == 'self': self.nDir = '' self.Count = 0 self.nSpeed = None self.dirState = '' debugPrint('---starting phrase') - debugPrint('callbackdepth %s, words: %s'%(natlink.getCallbackDepth(), words)) + debugPrint(f'callbackdepth {natlink.getCallbackDepth()}, words: {words}') if showAll: - self.DisplayMessage('<%s>'% ' '.join(words)) + self.DisplayMessage(f'<{" ".join(words)}>') else: - print('recogtype: %s'% recogType) + print(f'recogtype: {recogType}') self.inside = 0 def gotResults_reverse(self,words,fullResults): - debugPrint('reverse: %s'%repr(words)) + debugPrint(f'reverse: {words}') if self.nDir: self.flush() d = self.curDir @@ -506,13 +493,13 @@ def gotResults_reverse(self,words,fullResults): def gotResults_moveCount(self,words,fullResults): for w in words: if self.Count: self.flush() - debugPrint('moveCount: %s'%w) + debugPrint(f'moveCount: {w}') self.Count = int(w) def gotResults_mouseCount(self,words,fullResults): if self.Count: self.flush() for w in words: - debugPrint('mouseCount: %s'%w) + debugPrint(f'mouseCount: {w}') if w in Counts: self.Count = int(w) elif self.hasCommon(w, ('pixel', 'pixels')): @@ -528,7 +515,7 @@ def gotResults_mouseCount(self,words,fullResults): def gotResults_moveDir(self,words,fullResults): for w in words: - debugPrint('direction: %s'% w) + print(f'direction: {w}') if self.nDir: self.flush() d = '' @@ -544,7 +531,7 @@ def gotResults_moveDir(self,words,fullResults): def gotResults_searchDir(self,words,fullResults): for w in words: - debugPrint('direction: %s'% w) + debugPrint('direction: {w}') if self.nDir: self.flush() d = '' @@ -555,7 +542,7 @@ def gotResults_searchDir(self,words,fullResults): def gotResults_mouseDir(self,words,fullResults): for w in words: - debugPrint('mouseDir: %s'% w) + debugPrint('mouseDir: {w}') if w in ['up', 'omhoog']: d = 'up' elif w in ['down', 'omlaag']: d = 'down' elif w in ['right', 'rechts']: d = 'right' @@ -572,68 +559,64 @@ def gotResults_mouseDir(self,words,fullResults): self.minorState = newState def gotResults_endMoving(self,words,fullResults): - if self.nDir or self.Count or self.nSpeed != None: + if self.nDir or self.Count or self.nSpeed is not None: self.flush() - debugPrint('end moving: %s'% repr(words)) + debugPrint('end moving: {words}') for w in words: if w in ['hold','hold on', 'hold it', 'wacht']: self.waiting = 1 debugPrint('waiting mode') return - else: - self.cancelMode() + self.cancelMode() def gotResults_endMousing(self,words,fullResults): - if self.nDir or self.Count or self.nSpeed != None: + if self.nDir or self.Count or self.nSpeed is not None: self.flush() - debugPrint('end mousing: %s'% repr(words)) + debugPrint('end mousing: {words}') for w in words: if w in ['hold','hold on', 'hold it', 'wacht']: self.waiting = 1 debugPrint('waiting mode') return - else: - self.cancelMode() + self.cancelMode() if self.hasCommon(words, ['click', 'klik']): - natut.buttonClick() + natlinkutils.buttonClick() elif self.hasCommon(words, ['double click', 'dubbel klik']): - natut.buttonClick('left', 2) + natlinkutils.buttonClick('left', 2) def gotResults_endSearching(self,words,fullResults): - if self.nDir or self.Count or self.nSpeed != None: + if self.nDir or self.Count or self.nSpeed is not None: self.flush() - debugPrint('end searching: %s'% repr(words)) + debugPrint('end searching: {words}') for w in words: if w in ['hold','hold on', 'hold it', 'wacht']: self.waiting = 1 debugPrint('waiting mode') return - else: - self.cancelMode() - if self.hasCommon(words, ['cancel', 'annuleren']): - self.searchGoBack() + self.cancelMode() + if self.hasCommon(words, ['cancel', 'annuleren']): + self.searchGoBack() def gotResults_endRepeating(self,words,fullResults): - if self.nDir or self.Count or self.nSpeed != None: + if self.nDir or self.Count or self.nSpeed is not None: self.flush() - debugPrint('end repeating: %s'% repr(words)) + debugPrint('end repeating: {words}') for w in words: if w in ['hold','hold on', 'hold it', 'wacht']: self.waiting = 1 debugPrint('waiting mode') return - else: - self.cancelMode() + self.cancelMode() def gotResults_changeMoving(self,words,fullResults): - if self.nDir or self.Count or self.nSpeed != None: + if self.nDir or self.Count or self.nSpeed is not None: self.flush() b = r = '' for w in words: if b and r: - natut.playString("{"+r+b+"}") + sendkeys("{"+r+b+"}") b = r = '' if w in ['go on', 'ga door', 'ga verder', 'verder']: debugPrint('going on') @@ -654,11 +637,11 @@ def gotResults_changeMoving(self,words,fullResults): elif w in ['document']: r = 'ctrl+ext' if b and r: - natut.playString("{"+r+b+"}") + sendkeys("{"+r+b+"}") b = r = '' def gotResults_changeSearching(self,words,fullResults): - if self.nDir or self.Count or self.nSpeed != None: + if self.nDir or self.Count or self.nSpeed is not None: self.flush() for w in words: if w in ['go on', 'ga door', 'ga verder', 'verder', 'continue']: @@ -672,7 +655,7 @@ def gotResults_changeSearching(self,words,fullResults): self.state = 'moving' def gotResults_changeMousing(self,words,fullResults): - if self.nDir or self.Count or self.nSpeed != None: + if self.nDir or self.Count or self.nSpeed is not None: self.flush() for w in words: if w in ['go on', 'ga door', 'ga verder', 'verder', 'continue']: @@ -698,7 +681,7 @@ def gotResults_speed(self,words,fullResults): else: print('speed, invalid keyword:', w) self.nSpeed = max(min(self.nSpeed, 2), -2) - debugPrint ('speed words: %s, speed: %s' % (repr(words), self.nSpeed)) + debugPrint(f'speed words: {repr(words)}, speed: {self.nSpeed}') def gotResults_acceleration(self,words,fullResults): @@ -715,10 +698,10 @@ def gotResults_acceleration(self,words,fullResults): diff = -factor else: print('acceleration, invalid keyword:', w) - debugPrint ('acceleration, invalid keyword: %s'% w) + debugPrint ('acceleration, invalid keyword: {w}') self.nSpeed = self.nSpeed + diff self.nSpeed = max(min(self.nSpeed, 2), -2) - debugPrint ('acceleration words: %s, new speed: %s' % (repr(words), self.nSpeed)) + debugPrint(f'acceleration words: {repr(words)}, new speed: {self.nSpeed}') def gotResults_startMoving(self,words,fullResults): self.activateSet(['moving'], exclusive = 1) @@ -738,7 +721,7 @@ def gotResults_startSearching(self,words,fullResults): def gotResults_startMousing(self,words,fullResults): self.activateSet(['mousing'], exclusive = 1) - debugPrint('start mousing %s' % repr(words)) + debugPrint(f'start mousing {words}') if self.hasCommon(words, ["MUIS",'MOUSE']): self.state = 'mousing' if self.hasCommon(words, ["SLEEP",'DRAG']): @@ -746,10 +729,10 @@ def gotResults_startMousing(self,words,fullResults): xPos,yPos = natlink.getCursorPos() if self.hasCommon(words, ["SNELMENU",'RIGHT']): self.drag = 2 - natlink.playEvents([(natut.wm_rbuttondown,xPos,yPos)]) + natlink.playEvents([(natlinkutils.wm_rbuttondown,xPos,yPos)]) else: self.drag = 1 - natlink.playEvents([(natut.wm_lbuttondown,xPos,yPos)]) + natlink.playEvents([(natlinkutils.wm_lbuttondown,xPos,yPos)]) def gotResults_startRepeating(self,words,fullResults): self.state = 'repeating' @@ -795,16 +778,15 @@ def gotResults(self,words,fullResults): self.repeatNow() self.hadRepeat = 0 return - if self.Count or self.nSpeed != None or self.nDir: + if self.Count or self.nSpeed is not None or self.nDir: self.flush() if self.state in states: self.startNow() - debugPrint ('end of phrase (gotResults): %s'% repr(words)) + debugPrint ('end of phrase (gotResults): {words}') self.inside = 0 def flush(self): - debugPrint('flush, nDir: %s, Count: %s, nSpeed: %s'% - (self.nDir, self.Count, self.nSpeed)) + debugPrint(f'flush, nDir: {self.nDir}, Count: {self.Count}, nSpeed: {self.nSpeed}') if self.nDir: self.curDir = self.nDir self.nDir = '' @@ -816,7 +798,7 @@ def flush(self): self.Count = 0 return - if self.nSpeed != None: + if self.nSpeed is not None: self.curSpeed = self.nSpeed self.nSpeed = None self.waiting = 0 @@ -830,11 +812,11 @@ def moveMouse(self,direction,count): elif direction == 'left': xPos = xPos - count elif direction == 'right': xPos = xPos + count xSize,ySize = natlink.getScreenSize() - if xPos < 0: xPos = 0 + xPos = max(xPos, 0) if xPos >= xSize: xPos = xSize - 1 - if yPos < 0: yPos = 0 + yPos = max(yPos, 0) if yPos >= ySize: yPos = ySize - 1 - natlink.playEvents([(natut.wm_mousemove,xPos,yPos)]) + natlink.playEvents([(natlinkutils.wm_mousemove,xPos,yPos)]) # This turns on the tray icon depending on the movement direction. @@ -886,19 +868,19 @@ def setTrayIcon(self,toggleIcon): ## self.cancelMode() def repeatNow(self): - debugPrint('repeatNow: %s times, %s phrases' % (self.nTimes, self.nPhrase)) + debugPrint(f'repeatNow: {self.nTimes} times, {self.nPhrase} phrases') # put repeat mode ON: self.repeatFlag = 1 itemrange = list(range(len(self.lastResults))) if not itemrange: self.repeatFlag = 0 - return None + return itemrange = itemrange[-self.nPhrase:] #print 'na itemrange:', itemrange - for n in range(self.nTimes): + for _ in range(self.nTimes): for i in itemrange: if not self.repeatFlag: - return None # if something else happened + return # if something else happened self.repeatStuff= self.lastResults[i] natlink.recognitionMimic(self.repeatStuff) # reset repeat mode: @@ -915,25 +897,18 @@ def findKeyWord(list1,list2): return None startTime = time.time() -if DEBUG: - fOutName = 'c:\\DEBUG '+__name__+'.txt' - debugFile = open(fOutName, 'w') - print('DEBUG uitvoer naar: %s'% fOutName) def debugPrint(t): if not DEBUG: return - print('_gm: %s'% t) - if type(t) == bytes: - debugFile.write(t) - else: - debugFile.write(repr(t)) - debugFile.write('\n') - debugFile.flush() + print(t) + # debugFile.write(t) + # debugFile.write('\n') + # debugFile.flush() -iconDirectory = os.path.join(natqh.getUnimacroDirectory(), 'icons') +iconDirectory = os.path.join(status.getUnimacroDirectory(), 'icons') if not os.path.isdir(iconDirectory): - raise Exception('icon folder not present (for repeat and waiting icon): %s'% iconDirectory) + raise Exception('icon folder not present (for repeat and waiting icon): {iconDirectory}') # standard stuff Joel (adapted for possible empty gramSpec, QH, unimacro) thisGrammar = ThisGrammar() @@ -943,14 +918,16 @@ def debugPrint(t): thisGrammar = None def unload(): + #pylint:disable=W0603 global thisGrammar if thisGrammar: thisGrammar.unload() thisGrammar = None -def changeCallback(type,args): - # not active without special version of natlinkmain, - # call the cancelMode, to switch off exclusive mode when mic toggles: - if ((type == 'mic') and (args=='on')): - return # check WAS in natlinkmain... - if thisGrammar: - thisGrammar.cancelMode() +# def changeCallback(type,args): +# # not active without special version of natlinkmain, +# # call the cancelMode, to switch off exclusive mode when mic toggles: +# if ((type == 'mic') and (args=='on')): +# return # check WAS in natlinkmain... +# if thisGrammar: +# thisGrammar.cancelMode() + diff --git a/src/unimacro/UnimacroGrammars/_testtrayicon.py b/src/unimacro/OtherUnimacroGrammars/_testtrayicon.py similarity index 97% rename from src/unimacro/UnimacroGrammars/_testtrayicon.py rename to src/unimacro/OtherUnimacroGrammars/_testtrayicon.py index baa41f6..e3d8cc2 100644 --- a/src/unimacro/UnimacroGrammars/_testtrayicon.py +++ b/src/unimacro/OtherUnimacroGrammars/_testtrayicon.py @@ -1,4 +1,4 @@ -import natlinkutils +from natlinkcore import natlinkutils import natlink import os import os.path @@ -73,6 +73,8 @@ def onTrayIcon(self, message): thisGrammar = None def unload(): + #pylint:disable=W0603 global thisGrammar if thisGrammar: thisGrammar.unload() thisGrammar = None + diff --git a/src/unimacro/UnimacroGrammars/_unimacrotest.py b/src/unimacro/OtherUnimacroGrammars/_unimacrotest.py similarity index 88% rename from src/unimacro/UnimacroGrammars/_unimacrotest.py rename to src/unimacro/OtherUnimacroGrammars/_unimacrotest.py index 3cbdf38..c2ad4dc 100644 --- a/src/unimacro/UnimacroGrammars/_unimacrotest.py +++ b/src/unimacro/OtherUnimacroGrammars/_unimacrotest.py @@ -12,31 +12,22 @@ instance variables that are passed to all tests: -self.doAll (so the test knows it is a single test or a complete suite) - """ -__version__ = "$Rev: 561 $ on $Date: 2015-11-01 18:03:43 +0100 (zo, 01 nov 2015) $ by $Author: quintijn $" -# This file is part of a SourceForge project called "unimacro" see -# http://unimacro.SourceForge.net and http://qh.antenna.nl/unimacro -# (c) copyright 2003 see http://qh.antenna.nl/unimacro/aboutunimacro.html -# or the file COPYRIGHT.txt in the natlink\natlink directory -# -# This module was written by: Quintijn Hoogenboom (QH softwaretraining & advies) -# (started march 2007) -# - -import unittest -import natlink import os import sys -natqh = __import__('natlinkutilsqh') -natut = __import__('natlinkutils') -natbj = __import__('natlinkutilsbj') -import utilsqh +import unittest import glob -import actions +import natlink +from natlinkcore import natlinkstatus +import unimacro.natlinkutilsbj as natbj +from dtactions.unimacro import unimacroutils +from dtactions.unimacro import utilsqh +from dtactions.unimacro import unimacroactions as actions + +status = natlinkstatus.NatlinkStatus() class UnittestGrammar(natbj.IniGrammar): - language = natqh.getLanguage() + language = unimacroutils.getLanguage() name = 'unimacro test' iniIgnoreGrammarLists = ['tests'] # are set in this module gramSpec = """ @@ -77,7 +68,7 @@ def getTestNames(self): the result (the testNames) can then be filled in the list {tests} self.allTests (dict) contains the names: files entries """ - self.testFolder = os.path.join(natqh.getUnimacroDirectory(), "unimacro_test") + self.testFolder = os.path.join(status.getUnimacroDirectory(), "unimacro_test") testFiles = glob.glob(os.path.join(self.testFolder, "*test.py")) ## print 'testFiles: %s'% testFiles testNames = list(map(self.extractTestName, testFiles)) @@ -97,7 +88,7 @@ def showInifile(self): super(UnittestGrammar, self).showInifile(commandExplanation=commandExplanation) def doUnitTests(self, tests): - self.checkSysPath(self.testFolder) # append unimacro_test if needed + # self.checkSysPath(self.testFolder) # append unimacro_test if needed suiteAll = None self.activeTests = [] @@ -123,6 +114,12 @@ def doUnitTests(self, tests): def addUnitTest(self, test, fileName): """do one of the unittests""" ## actions.Message("starting test %s"% fileName) + + test_path = os.path.join(sys.prefix, 'Lib', 'site-packages', 'unimacro', 'unimacro_test') + if not os.path.isdir(test_path): + raise OSError(f'cannot add unittest for Unimacro, test_path invalid: "{test_path}"') + if not test_path in sys.path: + sys.path.append(test_path) modName = os.path.basename(fileName) modName = utilsqh.removeFromEnd(modName, ".py", ignoreCase=1) @@ -132,11 +129,10 @@ def addUnitTest(self, test, fileName): testClass = getattr(testMod, testClassName) except AttributeError: print('****cannot find test class in test module, skipping test: %s'% testClassName) - return + return None suite = unittest.makeSuite(testClass, 'test') return suite - def checkSysPath(self, folder): """add to sys.path if not present yet""" if folder in sys.path: @@ -192,7 +188,10 @@ def dumpResult(self, testResult, filesToSkip=None): thisGrammar = None def unload(): + #pylint:disable=W0603 global thisGrammar if thisGrammar: thisGrammar.unload() thisGrammar = None + + diff --git a/src/unimacro/UnimacroGrammars/excel.py b/src/unimacro/OtherUnimacroGrammars/excel.py similarity index 93% rename from src/unimacro/UnimacroGrammars/excel.py rename to src/unimacro/OtherUnimacroGrammars/excel.py index 321cbd8..e46ace5 100644 --- a/src/unimacro/UnimacroGrammars/excel.py +++ b/src/unimacro/OtherUnimacroGrammars/excel.py @@ -10,18 +10,19 @@ import natlink -natqh = __import__('natlinkutilsqh') -natut = __import__('natlinkutils') -natbj = __import__('natlinkutilsbj') +from dtactions.unimacro import unimacroutils +from natlinkcore import natlinkutils +from dtactions.unimacro import unimacroutils +import unimacro.natlinkutilsbj as natbj import pprint import types -from actions import doAction as action -from actions import doKeystroke as keystroke -import actions +from dtactions.unimacro.unimacroactions import doAction as action +from dtactions.unimacro.unimacroactions import doAction as action +from dtactions.unimacro import unimacroactions as actions import win32com # -language = natqh.getLanguage() +language = unimacroutils.getLanguage() ancestor = natbj.DocstringGrammar class ThisGrammar(ancestor): @@ -62,7 +63,7 @@ def gotBegin(self,moduleInfo): return else: self.prevHandle = winHandle - if natqh.matchModule('excel', modInfo=moduleInfo): + if unimacroutils.matchModule('excel', modInfo=moduleInfo): #print 'activate firefox %s mode'% mode if self.checkForChanges: print('excel (%s), checking the inifile'% self.name) @@ -77,7 +78,7 @@ def gotBegin(self,moduleInfo): return if self.isActive(): # refreshes current position now as well: - progInfo = natqh.getProgInfo(moduleInfo) + progInfo = unimacroutils.getProgInfo(moduleInfo) if self.excel is None: self.excel = actions.get_instance_from_progInfo(progInfo) if self.excel.app: @@ -200,7 +201,7 @@ def gotResults_before(self,words,fullResults): if not self.doWaitForMouseToStop(): print('excel, mouse does not stop, cancel command') return - natqh.buttonClick() + unimacroutils.buttonClick() def gotResults_date(self,words,fullResults): day = self.getNumberFromSpoken(words[1]) @@ -243,6 +244,8 @@ def printPositions(self, comment=None): thisGrammar = None def unload(): + #pylint:disable=W0603 global thisGrammar if thisGrammar: thisGrammar.unload() thisGrammar = None + diff --git a/src/unimacro/UnimacroGrammars/frescobaldi.py b/src/unimacro/OtherUnimacroGrammars/frescobaldi.py similarity index 96% rename from src/unimacro/UnimacroGrammars/frescobaldi.py rename to src/unimacro/OtherUnimacroGrammars/frescobaldi.py index 2653597..17b8e78 100644 --- a/src/unimacro/UnimacroGrammars/frescobaldi.py +++ b/src/unimacro/OtherUnimacroGrammars/frescobaldi.py @@ -47,14 +47,16 @@ """ -natqh = __import__('natlinkutilsqh') -natut = __import__('natlinkutils') -natbj = __import__('natlinkutilsbj') +from dtactions.unimacro import unimacroutils +import unimacro.natlinkutilsbj as natbj +from natlinkcore import natlinkutils +from dtactions.unimacro import unimacroutils +import unimacro.natlinkutilsbj as natbj import natlink -from actions import doAction as action -from actions import doKeystroke as keystroke +from dtactions.unimacro.unimacroactions import doAction as action +from dtactions.unimacro.unimacroactions import doAction as action from itertools import cycle -import actions +from dtactions.unimacro import unimacroactions as actions import re import copy import time @@ -81,9 +83,9 @@ def gotBegin(self, moduleInfo): winHandle = moduleInfo[2] if self.prevHandle == winHandle: return self.prevHandle = winHandle - if moduleInfo[0].lower().find('frescobaldi.exe') > 0 and natqh.isTopWindow(moduleInfo[2]): + if moduleInfo[0].lower().find('frescobaldi.exe') > 0 and unimacroutils.isTopWindow(moduleInfo[2]): if self.frescobaldi is None: - progInfo = natqh.getProgInfo(moduleInfo) + progInfo = unimacroutils.getProgInfo(moduleInfo) self.frescobaldi = actions.get_instance_from_progInfo(progInfo) if not self.frescobaldi: raise Exception("frescobaldi, cannot get frescobaldi actions module") @@ -120,7 +122,7 @@ def gotResultsInit(self,words,fullResults): self.justLeft = self.justRight = None # to be filled with getPrevNext() self.inMiddleOfWord = None if self.hasSelection: - print 'hasSelection, selected text: %s'% natqh.getClipboard() + print 'hasSelection, selected text: %s'% unimacroutils.getClipboard() self.hasAllInfoNext = False ## set to true if nextlines end with double \n self.hasAllInfoPrev = False ## set to true if prevlines contains a double \n so starts with ir @@ -258,8 +260,8 @@ def rule_figure(self, words): """here figure {figures}+""" # start with the pointer in the music pane # always click - natqh.buttonClick() - natqh.visibleWait() + unimacroutils.buttonClick() + unimacroutils.visibleWait() self.hadFigure = 1 selection = self.getFigurePart() @@ -366,7 +368,7 @@ def rule_notesinsert(self, words): ### ### position at correct position, possibly put a space. if self.hasCommon(words, 'here'): - natqh.buttonClick() + unimacroutils.buttonClick() self.getPrevNext() # position at left of word while self.inMiddleOfWord: @@ -388,7 +390,7 @@ def subrule_notesnavigate(self, words): # leave next|previous for the moment, assume always count from the beginning DIR = 'right' if self.hasCommon(words, 'here'): - natqh.buttonClick() + unimacroutils.buttonClick() try: nStr = self.getNumbersFromSpoken(words)[0] # returns a string or None n = int(nStr) @@ -652,7 +654,7 @@ def getPrevNextVariables(self, justLeft, justRight): def getFigurePart(self): # go left then right for selecting the note at the cursor position - natqh.saveClipboard() + unimacroutils.saveClipboard() self.getPrevNext() if self.justRight != "<": # go left until < has been reached: @@ -672,10 +674,10 @@ def getFigurePart(self): break else: print 'getFigurePart, did not find ">"' - natqh.restoreClipboard() + unimacroutils.restoreClipboard() return result = t - natqh.restoreClipboard() + unimacroutils.restoreClipboard() return result @@ -701,6 +703,7 @@ def fillInstanceVariables(self): thisGrammar = None def unload(): + #pylint:disable=W0603 global thisGrammar if thisGrammar: thisGrammar.unload() thisGrammar = None diff --git a/src/unimacro/UnimacroGrammars/solitaire.py b/src/unimacro/OtherUnimacroGrammars/solitaire.py similarity index 81% rename from src/unimacro/UnimacroGrammars/solitaire.py rename to src/unimacro/OtherUnimacroGrammars/solitaire.py index 87056b0..5b8d7c9 100644 --- a/src/unimacro/UnimacroGrammars/solitaire.py +++ b/src/unimacro/OtherUnimacroGrammars/solitaire.py @@ -25,24 +25,18 @@ # Written by: Quintijn Hoogenboom (QH softwaretraining & # advies),2002, revised October 2003 # march 2011: change sol to solitaire +#pylint:disable=C0209 +#pylint:disable=E0602 + """Grammar for playing solitaire (patience) hands-free Extensive use is made of mouse (dragging) routines. """ -import natlink import win32gui -import types -import time -import os -import os.path -import win32api -natqh = __import__('natlinkutilsqh') -natut = __import__('natlinkutils') -natbj = __import__('natlinkutilsbj') -from actions import doAction as action -from actions import doKeystroke as keystroke - +from natlinkcore import natlinktimer +from dtactions.unimacro import unimacroutils +import unimacro.natlinkutilsbj as natbj #aantal carden en aantal stapelplaatsen: cnum = list(range(1,8)) @@ -59,8 +53,6 @@ pauzesDelta = 0.1 minPause = 0.5 -language = natqh.getLanguage() - ancestor = natbj.DocstringGrammar class ThisGrammar(ancestor): name = 'solitaire' @@ -70,7 +62,6 @@ class ThisGrammar(ancestor): # """ def initialize(self): - global language if self.load(self.gramSpec): self.setNumbersList("cnum", cnum) self.setNumbersList("snum", snum) @@ -80,14 +71,12 @@ def initialize(self): self.pause = 1 self.inTimer = 0 self.pauseTime = 4 - else: - language = "" def cancelMode(self): #self.setExclusive(0) if self.inTimer: print('cancel timer') - natlink.setTimerCallback(None,0) + natlinktimer.setTimerCallback(self.onTimer,0) self.inTimer = 0 def onTimer(self): @@ -100,7 +89,7 @@ def onTimer(self): print('window handle changed, cancel timer') self.cancelMode() return - print('in onTimer: %.1f'% time.clock()) + # print('in onTimer: %.1f'% time.clock()) self.rule_newcard([]) @@ -108,9 +97,10 @@ def gotBegin(self,moduleInfo): print('gotbegin, cancelmode') self.cancelMode() winHandle = moduleInfo[2] - if self.prevHandle == winHandle: return + if self.prevHandle == winHandle: + return self.prevHandle = winHandle - if moduleInfo[0].lower().find('solitaire.exe') > 0 and natqh.isTopWindow(moduleInfo[2]): + if moduleInfo[0].lower().find('solitaire.exe') > 0 and unimacroutils.isTopWindow(moduleInfo[2]): if self.checkForChanges: print('grammar solitaire (%s) checking the inifile'% self.name) self.checkInifile() @@ -127,7 +117,7 @@ def gotResultsInit(self,words,fullResults): """ global hspace, vspace, cardhspace, cardvspace clrect = win32gui.GetClientRect(self.prevHandle) - xMax, yMax = clrect[2]-1, clrect[3]-1 + xMax, _yMax = clrect[2]-1, clrect[3]-1 hspace = (xMax - 7*kwidth)/8 cardhspace = int(hspace/2) cardvspace = vspace @@ -159,18 +149,18 @@ def rule_card(self, words): "card {cnum}" k = self.getNumberFromSpoken(words[-1]) self.moveTo(cardpos(k)) - natqh.buttonClick() + unimacroutils.buttonClick() # Draw a new card and position on the last opened card def rule_newcard(self, words): "'new card'|next|continue" self.moveTo(firstrowpos(1)) - natqh.buttonClick() + unimacroutils.buttonClick() self.moveTo(firstrowpos(2)) if self.hasCommon(words, 'continue'): timeEachMilliseconds = max(1, self.pauseTime)*500 print('set the timer to %s'% timeEachMilliseconds) - natlink.setTimerCallback(self.onTimer, timeEachMilliseconds) + natlinktimer.setTimerCallback(self.onTimer, timeEachMilliseconds) self.inTimer = 1 # Sometimes the mouse is a bit too high (if the stack grows longer) @@ -183,7 +173,7 @@ def rule_lower(self,words): pass elif self.hasCommon(words, 'higher'): d = -d - natqh.doMouse(0,2,0,d,0) + unimacroutils.doMouse(0,2,0,d,0) # Deze grammatica regel stelt de waittijd na elk (deel) van een # commando in. Zie "pauzes" bovenin dit standpunt @@ -198,28 +188,28 @@ def rule_to(self, words): "to ((stack {snum})|{cnum})" to = self.getNumberFromSpoken(words[-1]) - natqh.rememberMouse() + unimacroutils.rememberMouse() if self.hasCommon(words, 'stack'): to = firstrowpos(to+3) else: to = cardpos(to) self.dragTo(to) - natqh.cancelMouse() - natqh.buttonClick() + unimacroutils.cancelMouse() + unimacroutils.buttonClick() def rule_testposition(self, words): "test position ((stack {snum})|{cnum})" #test the stack and piles positions #lefttop = (0,0) - #natqh.doMouse(0, 5, 0,0, 'move') - #x, y = natqh.getMousePosition(1) + #unimacroutils.doMouse(0, 5, 0,0, 'move') + #x, y = unimacroutils.getMousePosition(1) #print 'screen x,y: %s, %s'% (x,y) - #x, y = natqh.getMousePosition(5) + #x, y = unimacroutils.getMousePosition(5) #print 'client: x,y: %s, %s'% (x,y) #time.sleep(2) to = self.getNumberFromSpoken(words[-1]) - natqh.rememberMouse() + unimacroutils.rememberMouse() if self.hasCommon(words, 'stack'): to = firstrowpos(to+3) @@ -235,17 +225,17 @@ def rule_cardnumto(self, words): #the first word is optional,and is recognised with the function #self.hasCommon, which can handle translations or synonyms print('cardnumto: %s'% words) - natqh.rememberMouse() - if self.hasCommon(words[0],['card']): - ww = words[1:] - else: - ww = words[:] + unimacroutils.rememberMouse() + # if self.hasCommon(words[0],['card']): + # ww = words[1:] + # else: + # ww = words[:] # go to numbered card with mouse: From = self.getNumberFromSpoken(words[0]) self.moveTo(cardpos(From)) - natqh.rememberMouse() + unimacroutils.rememberMouse() to = self.getNumberFromSpoken(words[-1]) # check if you go to a stack or another card column: @@ -254,15 +244,15 @@ def rule_cardnumto(self, words): else: to = cardpos(to) self.dragTo(to) - natqh.cancelMouse() - natqh.buttonClick() + unimacroutils.cancelMouse() + unimacroutils.buttonClick() def rule_cardto(self, words): "card to ((stack {snum})|{cnum})" #drag the last drawn card to a stack or to a pile print('cardto: %s'% words) - natqh.rememberMouse() + unimacroutils.rememberMouse() self.moveTo(firstrowpos(2)) to = self.getNumberFromSpoken(words[-1]) @@ -271,8 +261,8 @@ def rule_cardto(self, words): else: to = cardpos(to) self.dragTo(to) - natqh.cancelMouse() - natqh.buttonClick() + unimacroutils.cancelMouse() + unimacroutils.buttonClick() def gotResults(self,words,fullResults): """if stack auto, do after each move a {ctrl+a}""" @@ -286,21 +276,21 @@ def gotResults(self,words,fullResults): # At the top of this file the increment of the pausing is given. def Wait(self, t=None): if not t: - natqh.Wait(self.pause*pauzesDelta+minPause) + unimacroutils.Wait(self.pause*pauzesDelta+minPause) else: - natqh.Wait(t) + unimacroutils.Wait(t) # move to the given position and have a short wait: def moveTo(self, pos): - natqh.doMouse(0,5, pos[0], pos[1], 'move') + unimacroutils.doMouse(0,5, pos[0], pos[1], 'move') self.Wait() # drag from current position to the new position # Pause a few times, dependent on the pause state. def dragTo(self, pos): - xold,yold = natqh.getMousePosition(5) + xold,yold = unimacroutils.getMousePosition(5) print('hold down: %s, %s'% (xold, yold)) - natqh.doMouse(0,5,xold, yold, 'down') + unimacroutils.doMouse(0,5,xold, yold, 'down') xyincr = 50 nstepsx = int(abs(pos[0]-xold)/xyincr) nstepsy = int(abs(pos[1]-yold)/xyincr) @@ -309,18 +299,18 @@ def dragTo(self, pos): ysteps = int((pos[1]-yold)/nsteps) xsteps = int((pos[0]-xold)/nsteps) x, y = xold, yold - for i in range(nsteps): + for _ in range(nsteps): x += xsteps y += ysteps - natqh.doMouse(0,5, x, y, 'move') + unimacroutils.doMouse(0,5, x, y, 'move') self.Wait(0.01) if x != pos[0] or y != pos[1]: print('final move: %s, %s, %s, %s'% (x, pos[0], y, pos[1])) - natqh.doMouse(0,5, pos[0], pos[1], 'move') + unimacroutils.doMouse(0,5, pos[0], pos[1], 'move') self.Wait(0.01) - natqh.doMouse(0,5, pos[0], pos[1], 'move') + unimacroutils.doMouse(0,5, pos[0], pos[1], 'move') self.Wait(0.01) - natqh.releaseMouse() + unimacroutils.releaseMouse() self.Wait() @@ -356,15 +346,17 @@ def firstrowpos(i): thisGrammar = None def unload(): + #pylint:disable=W0603 global thisGrammar - if thisGrammar: thisGrammar.unload() + if thisGrammar: + thisGrammar.unload() thisGrammar = None -def changeCallback(type,args): - # not active without special version of natlinkmain, - # call the cancelMode, to switch off exclusive mode when mic toggles: - if ((type == 'mic') and (args=='on')): - return # check WAS in natlinkmain... - if thisGrammar: - print('cancel') - thisGrammar.cancelMode() +# def changeCallback(type,args): +# # not active without special version of natlinkmain, +# # call the cancelMode, to switch off exclusive mode when mic toggles: +# if ((type == 'mic') and (args=='on')): +# return # check WAS in natlinkmain... +# if thisGrammar: +# print('cancel') +# thisGrammar.cancelMode() diff --git a/src/unimacro/UnimacroGrammars/winword_variable.py b/src/unimacro/OtherUnimacroGrammars/winword_variable.py similarity index 87% rename from src/unimacro/UnimacroGrammars/winword_variable.py rename to src/unimacro/OtherUnimacroGrammars/winword_variable.py index 176cb45..aa4a17f 100644 --- a/src/unimacro/UnimacroGrammars/winword_variable.py +++ b/src/unimacro/OtherUnimacroGrammars/winword_variable.py @@ -8,10 +8,10 @@ # Quintijn, June 28, 2009 import natlink -natut = __import__('natlinkutils') +from natlinkcore import natlinkutils -ancestor = natut.GrammarBase +ancestor = natlinkutils.GrammarBase class ThisGrammar(ancestor): gramSpec = """ @@ -34,7 +34,7 @@ def gotBegin(self,moduleInfo): self.prevInfo = moduleInfo - winHandle = natut.matchWindow(moduleInfo,'winword','Microsoft Word') + winHandle = natlinkutils.matchWindow(moduleInfo,'winword','Microsoft Word') if winHandle: if not self.isActive(): self.activateAll() @@ -47,15 +47,17 @@ def gotResults_pasthistory(self, words, fullResults): for w in words: ## print 'got phword: %s'% w # including the trigger words! L.append(w) - natut.playString(' '.join(L)) + sendkeys(' '.join(L)) # standard stuff: thisGrammar = ThisGrammar() thisGrammar.initialize() def unload(): + #pylint:disable=W0603 global thisGrammar if thisGrammar: thisGrammar.unload() thisGrammar = None + diff --git a/src/unimacro/natspeak_dialog.py b/src/unimacro/OtherUnimacroGrammars/xxxxnatspeak_dialog.py similarity index 75% rename from src/unimacro/natspeak_dialog.py rename to src/unimacro/OtherUnimacroGrammars/xxxxnatspeak_dialog.py index 9a223ed..45930d8 100644 --- a/src/unimacro/natspeak_dialog.py +++ b/src/unimacro/OtherUnimacroGrammars/xxxxnatspeak_dialog.py @@ -8,24 +8,20 @@ # grammar activated if a recent folders dialog is brought to the foreground, # interaction with grammar _folders. # +#pylint:disable= +from dtactions.unimacro import unimacroutils +from dtactions.sendkeys import sendkeys as keystroke +import unimacro.natlinkutilsbj as natbj -import natlink -natut = __import__('natlinkutils') -natqh = __import__('natlinkutilsqh') -natbj = __import__('natlinkutilsbj') -from actions import doKeystroke as keystroke -from actions import doAction as action - - ancestor = natbj.IniGrammar class ThisGrammar(ancestor): """grammar recent folder dialog only to be switched on if dialog is there, if dialog is gone, the grammar rules set is deactivated """ - language = natqh.getLanguage() + language = unimacroutils.getLanguage() name = "natspeak dialog" setRecentFolderDialog = ["chooserfd", "okcancelrfd"] @@ -39,7 +35,7 @@ def initialize(self): print("no valid language in grammar "+__name__+" grammar not initialized") return self.load(self.gramSpec) - print('loaded: %s'% self.gramSpec) + print(f'loaded: {self.gramSpec}') self.prevHndle = None def gotBegin(self,moduleInfo): @@ -51,15 +47,15 @@ def gotBegin(self,moduleInfo): if hndle == self.prevHndle: return self.prevHndle = hndle - if natqh.matchModule('natspeak'): + if unimacroutils.matchModule('natspeak'): # try to reach data from _folders grammar: - self.foldersGram = natbj.GetGrammarObject('folders') + self.foldersGram = self.GetGrammarObject('folders') #print 'self.foldersGram: %s'% self.foldersGram if self.foldersGram is None: return dTitle = self.foldersGram.dialogWindowTitle dRange = self.foldersGram.dialogNumberRange - if dTitle and natqh.matchModule('natspeak', wantedTitle=dTitle, titleExact=1, caseExact=1): + if dTitle and unimacroutils.matchModule('natspeak', wantedTitle=dTitle, titleExact=1, caseExact=1): self.activateSet(self.setRecentFolderDialog) self.setNumbersList('number', dRange) return @@ -74,23 +70,23 @@ def gotResults_chooserfd(self, words, fullResults): """ wNumList = self.getNumbersFromSpoken(words) # returns a string or None if len(wNumList) != 1: - print('natspeak dialog: error in command, no number found: %s'% wNumList) + print(f'natspeak dialog: error in command, no number found: {wNumList}') return chooseNum = wNumList[0] self.exitDialog() self.foldersGram.gotoRecentFolder(chooseNum-1) # remember choose is 1 based, the list is 0 based def gotResults_okcancelrfd(self, words, fullResults): - print('dialog ok cancel: %s, just close the dialog'% words) + print(f'dialog ok cancel: {words}, just close the dialog') self.exitDialog() def exitDialog(self): """finish the open dialog, normally by pressing enter""" dTitle = self.foldersGram.dialogWindowTitle - if dTitle and natqh.matchModule('natspeak', wantedTitle=dTitle, titleExact=1, caseExact=1): - natqh.rememberWindow() + if dTitle and unimacroutils.matchModule('natspeak', wantedTitle=dTitle, titleExact=1, caseExact=1): + unimacroutils.rememberWindow() keystroke("{enter}") # exit dialog. - natqh.waitForNewWindow() + unimacroutils.waitForNewWindow() # standard stuff: @@ -98,6 +94,8 @@ def exitDialog(self): thisGrammar.initialize() def unload(): + #pylint:disable=W0603 global thisGrammar - if thisGrammar: thisGrammar.unload() + if thisGrammar: + thisGrammar.unload() thisGrammar = None diff --git a/src/unimacro/TrainDialog.py b/src/unimacro/TrainDialog.py index ec5bf05..85a2cb1 100644 --- a/src/unimacro/TrainDialog.py +++ b/src/unimacro/TrainDialog.py @@ -32,7 +32,7 @@ from pywin.framework import dlgappcore import natlink -from natlinkutils import * +from natlinkcore.natlinkutils import * from natlinkutilsbj import SetMic @@ -148,7 +148,7 @@ def gotResults_Buttons(self,words,fullResults): key='{Alt+c}' elif 'stop' in words: key='{Alt+p}' - natut.playString(key) + sendkeys(key) def gotResults_TrainButtons(self,words,fullResults): self.gotResults_Buttons(words,fullResults) @@ -158,7 +158,7 @@ def gotResults_ChangePhrase(self,words,fullResults): key='{Up}' elif 'skip' in words: key='{Down}' - natut.playString(key) + sendkeys(key) diff --git a/src/unimacro/UnimacroGrammars/README.txt b/src/unimacro/UnimacroGrammars/README.txt index d8eda97..8b86c67 100644 --- a/src/unimacro/UnimacroGrammars/README.txt +++ b/src/unimacro/UnimacroGrammars/README.txt @@ -1,16 +1,14 @@ -The python files in this folder are grammar files, which should be activated by copying or moving them into the UnimacroGrammarsDirectory, the subdirectory "ActiveGrammars" of the UnimacroUserDirectory +The python files in this folder are grammar files, which are activated, when starting Dragon with Natlink and Unimacro enabled. -In this directory, UnimacroGrammars, subdirectory of the UnimacroDirectory, will contain - as much as possible - maintained Unimacro grammars +These are the most common Unimacro grammars. They can be activated or deactivated by voice, through commands of the _control grammar. -After toggling the microphone the grammar should be active. In rare cases, this does not work. Restart Dragon in that case. +In other directories are more special or older (possibly obsolete) grammars and demo grammars. -Deactivating goes the other way around, simply remove from the UnimacroGrammarsDirectory (possibly move/copy them back to this directory), and again toggle the microphone. +When you want to activate these, specify with the config program a natlink userdirectory, and copy the grammars into this directory. (See the contents of the file natlink.ini) Note for unimacro grammar files it is also possible to activate/deactivate the grammars by voice commands as defined in _control. -Note: when developing grammars, do not forget to copy the last version from the "ActiveGrammars" directory (the UnimacroGrammarsDirectory) into the UnimacroGrammars directory here. - - +Quintijn Hoogenboom September 23, 2023 diff --git a/src/unimacro/UnimacroGrammars/__init__.py b/src/unimacro/UnimacroGrammars/__init__.py new file mode 100644 index 0000000..c369f13 --- /dev/null +++ b/src/unimacro/UnimacroGrammars/__init__.py @@ -0,0 +1,2 @@ +def locateme(): + return __path__[0] \ No newline at end of file diff --git a/src/unimacro/UnimacroGrammars/_brackets.py b/src/unimacro/UnimacroGrammars/_brackets.py index 2f8b37c..71a57b3 100644 --- a/src/unimacro/UnimacroGrammars/_brackets.py +++ b/src/unimacro/UnimacroGrammars/_brackets.py @@ -1,4 +1,3 @@ -__version__ = "$Rev: 571 $ on $Date: 2017-02-13 14:17:09 +0100 (ma, 13 feb 2017) $ by $Author: quintijn $" # This file is part of a SourceForge project called "unimacro" see # http://unimacro.SourceForge.net and http://qh.antenna.nl/unimacro # (c) copyright 2003 see http://qh.antenna.nl/unimacro/aboutunimacro.html @@ -6,44 +5,45 @@ # # _brackets.py # written by: Quintijn Hoogenboom (QH softwaretraining & advies) -# august 2003, revision october 2011 +# august 2003, revision october 2011, python3: september 2021 """ unimacro grammar that puts brackets, braces etc. -import rule -import "dgndictation" -import used. -import Unfortunately -import the -import other -import "imported -import rules" -(dgnletters and dgnwords) do not -work any more in Dragon 11 +Basically two ways are implemented: + +1. Say: "between brackets hello comma this is a test" +2. select text, and say "between brackets" +3. say "empty braces" +4. say "here parens" Notes: +====== 1. If you start or end with space-bar (or other white space), this will be put OUTSIDE the brackets. 2. No capitalisation is done unless you call as directive. -3. Dictation errors cannot be corrected with the spell window. Select, -dictate again and - correct then if needed. +3. Dictation errors cannot be corrected with the spell window. Select, +dictate again and then correct then if needed. + +Note: the natlinkclipboard module from dtactions is not ready for use. Use +the unimacroutils module of unimacro. + """ +#pylint:disable=C0115, C0116, W0201, W0613 +from natlinkcore import nsformat +from dtactions.unimacro import unimacroutils +from dtactions.unimacro.unimacroactions import doAction as action +from dtactions.unimacro.unimacroactions import doKeystroke as keystroke +# from dtactions.natlinkclipboard import Clipboard +import unimacro.natlinkutilsbj as natbj import natlink -import nsformat -natqh = __import__('natlinkutilsqh') -natbj = __import__('natlinkutilsbj') -natut = __import__('natlinkutils') -from actions import doAction as action -from actions import doKeystroke as keystroke -language = natqh.getLanguage() +language = unimacroutils.getLanguage() ancestor = natbj.DocstringGrammar class BracketsGrammar(ancestor): - language = natqh.getLanguage() + language = unimacroutils.getLanguage() name = "brackets" def initialize(self): @@ -62,9 +62,9 @@ def gotBegin(self,moduleInfo): def gotResultsInit(self, words, fullResults): self.dictated = '' # analysis of dgndictation or dgnletters self.pleft = self.pright = '' # the left and right parts of the brackets - + self.here, self.between, self.empty = False, False, False if self.mayBeSwitchedOn == 'exclusive': - print('recog brackets, switch off mic: %s'% words) + print(f'recog brackets, switch off mic: {words}') natbj.SetMic('off') def importedrule_dgndictation(self, words): @@ -78,7 +78,7 @@ def rule_brackets(self, words): p = self.getFromInifile(w, 'brackets') if not p: - print('no valid brackets found for word: "%s"'% w) + print(f'no valid brackets found for word: "{w}"') continue #print 'brackets, found: %s, %s'% (w, p) if len(p) > 2 and p.find("|") > 0: @@ -86,135 +86,127 @@ def rule_brackets(self, words): newpleft = pList[0] newpright = pList[1] else: - lenph = len(p)/2 + lenph = len(p)//2 newpleft, newpright = p[:lenph], p[lenph:] # make more brackets together, from outer to inner: self.pleft = self.pleft + newpleft self.pright = newpright + self.pright - #print 'pleft: "%s", pright: "%s"'% (repr(self.pleft), repr(self.pright)) + # print(f'result rule_brackets: |{self.pleft}|, pright: |{self.pright}|') def subrule_before(self, words): "(here|between|empty)+" - self.here, self.between = False, False + for w in words: if self.hasCommon(w, 'between'): # this is the trigger word, ignore self.between = True if self.hasCommon(w, 'here'): # this is the trigger word, ignore self.here = True if self.hasCommon(w, 'empty'): # this is the trigger word, ignore - self.between = False - + self.empty = True + def gotResults(self, words, fullResults): # see if something selected, leaving the clipboard intact # keystroke('{ctrl+x}') # try to cut the selection - if self.between: - natqh.saveClipboard() - action('<>') - contents = natlink.getClipboard().replace('\r','') - natqh.restoreClipboard() - else: - contents = "" + # if no text is dictated, self.dictated = "" + text, leftTextDict, rightTextDict = stripFromBothSides(self.dictated) if self.here: - natqh.buttonClick('left', 1) - natqh.visibleWait() - - leftText = rightText = leftTextDict = rightTextDict = "" - if contents: - # strip from clipboard contents: - contents, leftText, rightText = self.stripFromBothSides(contents) - - if self.dictated.strip(): - contents, leftTextDict, rightTextDict = self.stripFromBothSides(self.dictated) - elif self.dictated: - # the case of only a space-bar: - leftTextDict = self.dictated - - - lSpacing = leftText + leftTextDict - rSpacing = rightTextDict + rightText - - if lSpacing: - keystroke(lSpacing) - - action(self.pleft) - natqh.visibleWait() - if contents: - #print 'contents: |%s|'% repr(contents) - keystroke(contents) - natqh.visibleWait() - action(self.pright) - natqh.visibleWait() - - if rSpacing: - keystroke(rSpacing) + print('do a left buttonClick') + unimacroutils.buttonClick('left', 1) + unimacroutils.visibleWait() - if not contents: - # go back so you stand inside the brackets: - nLeft = len(self.pright) + len(rSpacing) - keystroke('{ExtLeft %s}'% nLeft) + if self.empty: + if self.dictated: + print(f'_brackets, warning, dictated text "{self.dictated}" is ignored, because of keyword "empty"') + self.do_keystrokes_brackets() + return + + # only if no dictated text, try to cut the selection (if there, add one char for safety with + # the clipboard actions, only fails when at end of file) + if not self.dictated: + unimacroutils.saveClipboard() + keystroke('{shift+right}') # take one extra char for the clipboard to hit + action('<>') + action('W') + cb_text = unimacroutils.getClipboard() + unimacroutils.restoreClipboard() + if cb_text: + text, lastchar = cb_text[:-1], cb_text[-1] + else: + action('<>') + raise OSError('no value in clipboard, restore cut text') + print(f'_brackets, got from clipboard: "{text}" + extra char: "{lastchar}"') + self.do_keystrokes_brackets(text=text, lastchar=lastchar) + return - def stripFromBothSides(self, text): - """strip whitespace from left side and from right side and return -the three parts - - input: text - output: stripped, leftSpacing, rightSpacing - """ - leftText = rightText = "" - lSpaces = len(text) - len(text.lstrip()) - leftText = rightText = "" - if lSpaces: - leftText = text[:lSpaces] - text = text.lstrip() - rSpaces = len(text) - len(text.rstrip()) - if rSpaces: - rightText = text[-rSpaces:] - text = text.rstrip() - return text, leftText, rightText - - - def fillDefaultInifile(self, ini): - """filling entries for default ini file + self.do_keystrokes_brackets(text=text, l_spacing=leftTextDict, r_spacing=rightTextDict) +# + def do_keystrokes_brackets(self, text='', lastchar='', l_spacing='', r_spacing=''): + """do the pleft text pright keystrokes with spacing issues + + handle the "between" keyword here! """ - if self.language == 'nld': - ini.set('brackets', 'aanhalingstekens', '""') - ini.set('brackets', 'kwoots', "''") - ini.set('brackets', 'brekkits', '[]') - ini.set('brackets', 'haakjes', '()') - ini.set('brackets', 'punt haakjes', '<>') - ini.set('brackets', 'driedubbele aanhalingstekens', '""""""') - ini.set('brackets', 'accolades', '{}') - ini.set('brackets', 'html punt haakjes', "<|>") - ini.set('brackets', 'html brekkits', "[|]") - else: - ini.set('brackets', 'double quotes', '""') - ini.set('brackets', 'quotes', "''") - ini.set('brackets', 'single quotes', "''") - ini.set('brackets', 'square brackets', '[]') - ini.set('brackets', 'brackets', '()') - ini.set('brackets', 'parenthesis', '()') - ini.set('brackets', 'backticks', '``') - ini.set('brackets', 'parens', '()') - ini.set('brackets', 'angle brackets', '<>') - ini.set('brackets', 'triple quotes', '""""""') - ini.set('brackets', 'html angle brackets', "<|>") - ini.set('brackets', 'html square brackets', "[|]") - ini.set('brackets', 'braces', '{}') - -# standard stuff Joel (adapted for possible empty gramSpec, QH, unimacro) -bracketsGrammar = BracketsGrammar() -if bracketsGrammar.gramSpec: - bracketsGrammar.initialize() -else: - bracketsGrammar = None + keystroke(l_spacing) + keystroke(self.pleft) + unimacroutils.visibleWait() + if text: + keystroke(text) + unimacroutils.visibleWait() + keystroke(self.pright) + keystroke(r_spacing) + if lastchar: + keystroke(lastchar) + keystroke("{left %s}"% len(lastchar)) + if self.between: + keystroke("{left %s}"% len(self.pright)) + +def stripFromBothSides(text): + """strip whitespace from left side and from right side and return +the three parts + input: text + output: stripped, leftSpacing, rightSpacing + """ + if not text: + return "", "", "" + leftText = rightText = "" + lSpaces = len(text) - len(text.lstrip()) + leftText = rightText = "" + if lSpaces: + leftText = text[:lSpaces] + text = text.lstrip() + rSpaces = len(text) - len(text.rstrip()) + if rSpaces: + rightText = text[-rSpaces:] + text = text.rstrip() + return text, leftText, rightText + +# standard stuff Joel (adapted in course of time, QH) def unload(): + #pylint:disable=W0603, E0601 global bracketsGrammar - if bracketsGrammar: bracketsGrammar.unload() + if bracketsGrammar: + bracketsGrammar.unload() bracketsGrammar = None + + +if __name__ == "__main__": + natlink.natConnect() + try: + bracketsGrammar = BracketsGrammar(inifile_stem='_brackets') + bracketsGrammar.startInifile() + bracketsGrammar.initialize() + finally: + natlink.natDisconnect() +else: + bracketsGrammar = BracketsGrammar() + if bracketsGrammar.gramSpec: + bracketsGrammar.initialize() + else: + bracketsGrammar = None + diff --git a/src/unimacro/UnimacroGrammars/_clickbyvoice.py b/src/unimacro/UnimacroGrammars/_clickbyvoice.py index ea9328f..26bd705 100644 --- a/src/unimacro/UnimacroGrammars/_clickbyvoice.py +++ b/src/unimacro/UnimacroGrammars/_clickbyvoice.py @@ -18,6 +18,8 @@ # # the lists {pagecommands} and {tabcommands} in the inifile (edit chrome hah) # +#pylint:disable=C0209 + """ This commands grammar allows clicking by voice @@ -25,19 +27,16 @@ in the foreground """ - - import natlink -natqh = __import__('natlinkutilsqh') -natut = __import__('natlinkutils') -natbj = __import__('natlinkutilsbj') -from actions import doAction as action -from actions import doKeystroke as keystroke +from unimacro import natlinkutilsbj as natbj +from dtactions.unimacro import unimacroutils +from dtactions.unimacro.unimacroactions import doAction as action +from dtactions.unimacro.unimacroactions import doKeystroke as keystroke # use extension Click by Voice visiblePause = 0.4 -language = natqh.getLanguage() +language = unimacroutils.getLanguage() ancestor = natbj.IniGrammar class ThisGrammar(ancestor): @@ -55,52 +54,62 @@ class ThisGrammar(ancestor): gramSpec = """ exported = ((show) (numbers) [{additionalonoroff}]+) | ((numbers) {additionalonoroff}+) ; - exported = (hide) (numbers) [after {n1-20}]; + exported = (hide) (numbers); exported = (pick) [{navigateoptions}]; +# is already in _tasks grammar: +# exported = ((next|previous) tab) [{n1-20} | {tabcommands}]| +# (tab (back|forward) [{n1-20} | {tabcommands}]); +# exported = tab {n1-n20} [{tabcommands}]; +# exported = tab {tabcommands}; + + exported = ((next|previous|{pagecommands}) page)| (page (back|forward) [{n1-20}]) | page {pagecommands} | (next|previous) page {pagecommands}; + #and the numbers grammar (0,...,999 or chain of digits): """+numberGram def initialize(self): self.prevHandle = -1 + self.ActiveHndle = None self.load(self.gramSpec) def gotBegin(self,moduleInfo): - if not language: return + if not language: + return if self.checkForChanges: self.prevHandle = None winHandle = moduleInfo[2] if not winHandle: - print('no window handle in %s'% self.name) + print(f'no window handle in {self.name}') return if self.prevHandle == winHandle: return self.prevHandle = winHandle - progInfo = natqh.getProgInfo(moduleInfo) + progInfo = unimacroutils.getProgInfo(moduleInfo) # print('progInfo: %s'% repr(progInfo)) prog = progInfo.prog chromiumBrowsers = {'chromium', 'chrome', 'msedge', 'safari', 'brave'} if prog in chromiumBrowsers: - if progInfo.topchild == 'child': - print('in child window, the clickbyvoice window?') + if progInfo.toporchild == 'child': + print(f'in child window, of a clickbyvoice program {prog}') if self.checkForChanges: - print('_clickbyvoice (%s), prog: %s, checking the inifile'% (self.name, prog)) + print(f'_clickbyvoice ({self.name}, prog: {prog}, checking the inifile') self.checkInifile() self.switchOnOrOff(window=winHandle) - if not self.isActive == winHandle: - print("activate _clickbyvoice, %s, %s"% (prog, winHandle)) + if not self.ActiveHndle == winHandle: + print(f'activate _clickbyvoice, {prog}, hndle: {winHandle}') self.activateAll(window=winHandle) - self.isActive = winHandle + self.ActiveHndle = winHandle else: - if self.isActive: + if self.isActive(): print("deactivate _clickbyvoice") self.deactivateAll() - self.isActive = False + self.ActiveHndle = False def gotResultsInit(self,words,fullResults): @@ -127,9 +136,10 @@ def gotResults_shownumbers(self, words, fullResults): additionalOptions = False while 1: additional = self.getFromInifile(words[-1], 'additionalonoroff', noWarning=1) - if additional is None: break + if additional is None: + break if additional == '-': - print('%s: hide the numbers'% self.name) + print(f'{self.name}: hide the numbers') self.gotResults_hidenumbers(words, fullResults) return words.pop() # remove last word of list. @@ -140,42 +150,90 @@ def gotResults_shownumbers(self, words, fullResults): additionalOptions = True if additionalOptions: - print('%s: showNumbers command: %s, set as new default for the current session.'% (self.name, showNumbers)) + print(f'{self.name}: showNumbers command: {showNumbers}, set as new default for the current session.') # set new chosen string: # self.setInInifile("general", "show numbers", showNumbers) self.showNumbers = showNumbers self.getInputcontrol() self.doOption(showNumbers) + print('clickbyvoice, before finishInputControl') self.finishInputControl() - + print('clickbyvoice, after finishInputControl') + def gotResults_hidenumbers(self, words, fullResults): """hide the numbers """ - wordFound, position = self.hasCommon(words, "after", withIndex=True) - if wordFound: - print("setting timer later") - self.getInputcontrol() self.doOption(self.hideNumbers) self.finishInputControl() + def gotResults_tabactions(self,words,fullResults): + """do an actions to the current tab (doc)""" + # print(f'tabactions words: {words}') + command = self.getFromInifile(words, 'tabcommands') + + if command: + action(command) + + def gotResults_numberedtabs(self,words,fullResults): + """go to a numbered tab (doc) and do an optional action""" + print(f'numberedtabs: {words}') + command = self.getFromInifile(words, 'tabcommands') + + counts = self.getNumbersFromSpoken(words) + if not counts: + print(f'_clickbyvoice, numberedtabs, no valid tab number found: {words}') + return + + if command: + action(command) + + def gotResults_navigatetabs(self,words,fullResults): + """go to next or previous tab(s) (documents) and refresh possibly""" + print(f'navigate tabs: {words}') + direction = None + command = self.getFromInifile(words, 'tabcommands',noWarning=1) + + if self.hasCommon(words, ['next', 'verder', 'volgende', 'vooruit', 'forward']): + direction = 'tab' + elif self.hasCommon(words, ['previous', 'terug', 'vorige', 'back']): + direction = 'shift+tab' + else: + print(f'no direction found in command: {words}') + + counts = self.getNumbersFromSpoken(words) + if counts: + count = counts[0] + else: + count = 1 +## print 'tabs: direction: %s, count: |%s|, command: |%s|'% (direction, counlinker balkt, command) + + if direction: + while count > 0: + count -= 1 + keys = '{ctrl+' + direction + '}' + keystroke(keys) + unimacroutils.Wait(0.5) #0.3 seem too short for going back tabs in chrome + + if command: + action(command) def gotResults_navigatepages(self,words,fullResults): """go to next or previous page(s) and refresh possibly""" ## print 'navigate pages: %s'% words ## not active at the moment, possibly reactivate... - dir = None + direction = None command = self.getFromInifile(words, 'pagecommands',noWarning=1) if self.hasCommon(words, ['next', 'verder', 'volgende', 'vooruit', 'forward']): - dir = 'right' + direction= 'right' elif self.hasCommon(words, ['previous', 'terug', 'vorige', 'back']): - dir = 'left' + direction= 'left' else: - print('no direction found in command: %s'% words) + print(f'no direction found in command: {words}') counts = self.getNumbersFromSpoken(words) if counts: @@ -184,11 +242,11 @@ def gotResults_navigatepages(self,words,fullResults): count = 1 ## print 'PAGES: dir: %s, count: |%s|, command: |%s|'% (dir, counlinker balkt, command) - if dir: + if direction: while count > 0: count= count -1 - keystroke('{alt+%s}'%(dir)) - natqh.Wait(0.5) #0.3 seem too short for going back pages in chrome + keystroke('{alt+%s}'%(direction)) + unimacroutils.Wait(0.5) #0.3 seem too short for going back pages in chrome if command: action(command) @@ -212,13 +270,13 @@ def gotResults(self,words,fullResults): command += ":" command += self.navOption if command.find(';') >= 0: - print('command: %s'% command) + print(f'command: {command}') commandparts = command.split(';') command = commandparts.pop(0) - print('command: %s, commandparts: %s'% (command, commandparts)) + print(f'command: {command}, commandparts: {commandparts}') self.doOption(command) for additional in commandparts: - natqh.Wait(visiblePause) + unimacroutils.Wait(visiblePause) keystroke(additional) self.finishInputControl() @@ -227,17 +285,18 @@ def gotResults(self,words,fullResults): def getInputcontrol(self): """get the Click by Voice input control""" keystroke("{shift+ctrl+space}") - natqh.Wait() ## longer: natqh.Wait(visiblePause) + unimacroutils.Wait() ## longer: unimacroutils.Wait(visiblePause) for i in range(10): - progInfo = natqh.getProgInfo() - if progInfo.topchild == 'child': - if i: print('found input window after %s steps'% i) + progInfo = unimacroutils.getProgInfo() + if progInfo.toporchild == 'child': + if i: + print(f'found input window after {i} steps') break - natqh.Wait() + unimacroutils.Wait() else: print("_clickbyvoice failed to reach input window") # print("found input window of clickbyvoice") - natqh.visibleWait() + unimacroutils.visibleWait() def doOption(self, option): @@ -247,8 +306,8 @@ def doOption(self, option): def finishInputControl(self): """press enter, after a little bit of waiting """ - natqh.visibleWait() - natqh.visibleWait() + unimacroutils.visibleWait() + unimacroutils.visibleWait() keystroke("{enter}") def fillInstanceVariables(self): @@ -256,14 +315,14 @@ def fillInstanceVariables(self): """ self.showNumbers = self.ini.get('general', 'show numbers') or ':+' - if not self.showNumbers.find(":") == 0: + if self.showNumbers.find(":") != 0: if self.showNumbers.find(":") == -1: self.showNumbers = ":" + self.showNumbers else: - print('%s, "+" sign missing in inifile, "general", "show numbers": "%s", replace by default: "%s"'% (self.name, self.showNumbers, ":+")) + print(f'{self.name}, "+" sign missing in inifile, "general", "show numbers": "{self.showNumbers}", replace by default: ":+"') self.showNumbers = ":+" if self.showNumbers.find("+") != 1: - print('%s, "+" sign missing or in wrong position in inifile, "general", "show numbers": "%s", replace by default: "%s"'% (self.name, self.showNumbers, ":+")) + print('{self.name}, "+" sign missing or in wrong position in inifile, "general", "show numbers": "{self.showNumbers}", replace by default: ":+"') self.showNumbers = ":+" # not in inifile: self.hideNumbers = ":-" @@ -271,13 +330,31 @@ def fillInstanceVariables(self): # standard stuff Joel (adapted for possible empty gramSpec, QH, unimacro) -thisGrammar = ThisGrammar() -if thisGrammar.gramSpec: +if __name__ == "__main__": + ## interactive use, for debugging: + with natlink.natConnect(): + try: + thisGrammar = ThisGrammar(inifile_stem="_clickbyvoice") + # thisGrammar.startInifile() + thisGrammar.initialize() + print('clickbyvoice, before finishInputControl') + thisGrammar.finishInputControl() + print('clickbyvoice, after finishInputControl') + + + + finally: + thisGrammar.unload() +elif __name__.find('.') == -1: + # standard startup when Dragon starts: + thisGrammar = ThisGrammar() thisGrammar.initialize() -else: - thisGrammar = None + def unload(): + #pylint:disable=W0603 global thisGrammar - if thisGrammar: thisGrammar.unload() + if thisGrammar: + thisGrammar.unload() thisGrammar = None + diff --git a/src/unimacro/UnimacroGrammars/_debug_natlink.py b/src/unimacro/UnimacroGrammars/_debug_natlink.py.txt similarity index 73% rename from src/unimacro/UnimacroGrammars/_debug_natlink.py rename to src/unimacro/UnimacroGrammars/_debug_natlink.py.txt index 6e76745..95b3a63 100644 --- a/src/unimacro/UnimacroGrammars/_debug_natlink.py +++ b/src/unimacro/UnimacroGrammars/_debug_natlink.py.txt @@ -1,21 +1,22 @@ """ Grammar to help with natlink hosted python debugging. """ - +#pylint:disable=W0611, W0613, C0115, C0116 import natlink -import natlinkpydebug as pd -import natlinkutilsqh as natqh -import natlinkutils as natut -import natlinkutilsbj as natbj -# import gramparser as gp -from actions import doAction as action -import nsformat +from natlinkcore import natlinkpydebug as pd +from natlinkcore import natlinkutils +from natlinkcore import gramparser as gp +from natlinkcore import nsformat + +# import unimacro.natlinkutilsbj as natbj -ancestor = natbj.IniGrammar #QH1 +# from dtactions.unimacro import unimacroutils +# from dtactions.unimacro.unimacroactions import doAction as action -class DebugGrammar(ancestor): - # language = natqh.getLanguage() +# ancestor = natbj.IniGrammar #QH1 +class DebugGrammar(natlinkutils.GrammarBase): + # language = unimacroutils.getLanguage() name = "Natlink Debug" gramSpec = """ exported = debug ; @@ -33,9 +34,9 @@ class DebugGrammar(ancestor): # ancestor.__init__(self,self.gramSpec,self.name) ## should be ancestor.__init__(self) only. but not needed. def initialize(self): - print(f"debug initialize, by loading self.gramSpec") + print('debug initialize, by loading self.gramSpec') self.load(self.gramSpec) - self.switchOnOrOff() ## based on the ini settings, by default, on + self.activateAll() @@ -68,12 +69,15 @@ def gotBegin(self,moduleInfo): # standard stuff Joel (adapted for possible empty gramSpec, QH, unimacro) debug_grammar = DebugGrammar() if debug_grammar.gramSpec: - print(f'debug_grammar initialize') + print('debug_grammar initialize') debug_grammar.initialize() else: - print(f'debug_grammar not initialize, no gramSpec found') + print('debug_grammar not initialize, no gramSpec found') debug_grammar = None def unload(): + #pylint:disable=W0603 global debug_grammar - debug_grammar = None \ No newline at end of file + debug_grammar = None + + diff --git a/src/unimacro/UnimacroGrammars/_debug_unimacro.py.txt b/src/unimacro/UnimacroGrammars/_debug_unimacro.py.txt new file mode 100644 index 0000000..4611772 --- /dev/null +++ b/src/unimacro/UnimacroGrammars/_debug_unimacro.py.txt @@ -0,0 +1,54 @@ +""" +Grammar to help with natlink hosted python debugging. +""" + + +import natlink +import natlinkutilsqh as natqh +import natlinkutils as natut +import natlinkutilsbj as natbj +# import gramparser as gp +from actions import doAction as action +import nsformat + +ancestor = natbj.IniGrammar #QH1 + +class DebugGrammar(ancestor): + # language = natqh.getLanguage() + name = "Natlink Debug" + gramSpec = """ + exported = debug starter; ## extra rule + exported = debug ; + = ; + exported = code ; + = Info | Start; +""" + # def __init__(self):n ##QH2 + # return print(f"debug __init__ ") + # ancestor.__init__(self,self.gramSpec,self.name) ## should be ancestor.__init__(self) only. but not needed. + + def initialize(self): + print(f"debug initialize, by loading self.gramSpec") + self.load(self.gramSpec) + self.switchOnOrOff() ## based on the ini settings, by default, on + + def gotResults_starter(self,words,fullResults): ## extra result + print(f"debug starter caught") + def gotResults_debug(self,words,fullResults): + print(f"debug gotResults_results words: {words} {fullResults} ") + def gotBegin(self,moduleInfo): + return print(f"debug gotBegin moduleInfo {moduleInfo}") + +#unsure if required Yes, this IS the way! +# standard stuff Joel (adapted for possible empty gramSpec, QH, unimacro) +debug_grammar = DebugGrammar() +if debug_grammar.gramSpec: + print(f'debug_grammar initialize') + debug_grammar.initialize() +else: + print(f'debug_grammar not initialize, no gramSpec found') + debug_grammar = None + +def unload(): + global debug_grammar + debug_grammar = None \ No newline at end of file diff --git a/src/unimacro/UnimacroGrammars/_folders fillinstancevariables.txt b/src/unimacro/UnimacroGrammars/_folders fillinstancevariables.txt new file mode 100644 index 0000000..b089af3 --- /dev/null +++ b/src/unimacro/UnimacroGrammars/_folders fillinstancevariables.txt @@ -0,0 +1,151 @@ +fillinstancevariables old: + def fillInstanceVariables(self): + """fills the necessary instance variables + take the lists of folders, virtualdrives (optional) and remotedrives (optional). + + """ + #pylint:disable=R0914 + self.useOtherExplorer = self.ini.get('general', 'use other explorer') + if self.useOtherExplorer: + if os.path.isfile(self.useOtherExplorer): + print('_folders, use as default explorer: "%s"'% self.useOtherExplorer) + else: + print('_folders, variable "use other explorer" set to: "%s" (use data from "actions.ini")'% self.useOtherExplorer) + + ## callback time in seconds: + interval = self.ini.getFloat('general', 'track folders interval') + if interval: + self.trackFoldersInterval = int(interval*1000) # give in seconds + else: + self.trackFoldersInterval = 4000 # default 4 seconds + + self.recentfoldersDict = {} + inipath = self.ini.getFilename() + if inipath.endswith('.ini'): + _changingDataIniPath = inipath.replace(".ini", "changingdata.pickle") + self.pickleChangingData = inipath.replace(".ini", "changingdata.pickle") + else: + self.pickleChangingData = "" + + ## automatic tracking of recent folders : + self.trackFoldersHistory = self.ini.getInt('general', 'track folders history') + if self.trackFoldersHistory: + if self.pickleChangingData: + self.recentfoldersDict = self.loadRecentFoldersDict() + if self.recentfoldersDict: + print("recentfolders, set %s keys from _folderschangingdata.pickle"% len(self.recentfoldersDict)) + else: + print("recentfolder, no previous recentfolders cached in _folderschangingdata.pickle") + + self.doTrackFoldersHistory = True # can be started or stopped with command + # recent [folders] START or recent [folders] STOP + intervalSeconds = self.trackFoldersInterval/1000 + print('maintain a list of %s recent folders (Explorer or File Dialog) at every utterance and every %s seconds'% (self.trackFoldersHistory, intervalSeconds)) + natlinktimer.setTimerCallback(self.catchTimerRecentFolders, self.trackFoldersInterval) # every 5 seconds + else: + self.doTrackFoldersHistory = False + if self.doTrackFoldersHistory: + rfList = self.ini.get('recentfolders') + for key in rfList: + value = self.ini.get('recentfolders', key) + self.recentfoldersDict[key] = value + # extract special variables from ini file: + self.virtualDriveDict = {} + wantedVirtualDriveList = self.ini.get('virtualdrives') + if wantedVirtualDriveList: + self.resolveVirtualDrives(wantedVirtualDriveList) + self.virtualDriveList = list(self.virtualDriveDict.keys()) + # print '_folders, virtual drives from dict: %s'% repr(self.virtualDriveDict) + # print '_folders, virtual drives from list: %s'% ', '.join(self.virtualDriveList) + + # checking the passes of all folders: + foldersList = self.ini.get('folders') + self.foldersDict = {} + for f in foldersList: + raw_folder = self.ini.get('folders', f) + folder = self.substituteFolder(raw_folder) + if not os.path.isdir(folder): + print(f'warning _folders, folder "{f}" does not exist: "{folder}"') + # self.ini.delete('folders', f) + # self.ini.set('obsolete folders', f, folder) + continue + self.foldersDict[f] = folder + + # track virtual drives if in ini file: + self.trackFolders = self.ini.getList('general', 'track folders virtualdrives') + self.trackFiles = self.ini.getList('general', 'track files virtualdrives') + # below this threshold, the getting of subfolders and files in a directory is not printed in the messages window + self.notifyThresholdMilliseconds = self.ini.getInt("general", "notify threshold milliseconds", 50) + # print("_folders, notify threshold milliseconds: %s"% self.notifyThresholdMilliseconds) + # in order to accept .py but it should be (for fnmatch) *.py etc.: + self.acceptFileExtensions = self.ini.getList('general', 'track file extensions') + self.ignoreFilePatterns = self.ini.getList('general', 'ignore file patterns') + + # these are for automatic tracking the current folder: + self.trackAutoFolders = self.ini.getBool('general', 'automatic track folders') + self.trackAutoFiles = self.ini.getBool('general', 'automatic track files') + + self.foldersSections = ['folders'] + # track folders: + for trf in self.trackFolders: + if not trf: + continue + trf2 = self.substituteFolder(trf) + #print 'input: %s, output: %s'% (trf, trf2) + if not os.path.isdir(trf2): + print('warning, no valid folder associated with: %s (%s) (skip for track virtualdrives)'% (trf, trf2)) + continue + #else: + # print 'valid folder for tracking: %s (%s)'% (trf, trf2) + subf = [f for f in os.listdir(trf2) if os.path.isdir(os.path.join(trf2, f))] + self.trackFoldersSection = 'folders %s'% trf + self.ini.delete(self.trackFoldersSection) # not in inifile + self.foldersSections.append(self.trackFoldersSection) + self.acceptVirtualDrivesFolder(trf, trf2) # without f, take virtualdrive itself... + for f in subf: + ## if no strange signs in folder name: + self.acceptVirtualDrivesFolder(trf, trf2, f) + #self.cleanupIniFoldersSection(self.trackFoldersSection, trf) + #self.removeObsoleteIniSections(prefix="folders ", validPostfixes=self.trackFolders) + self.removeObsoleteIniSections(prefix="folders ", validPostfixes=[]) # do not keep in ini file + + # do the files: + self.filesDict = {} + self.trackFiles = self.ini.getList('general', 'track files virtualdrives') + # in order to accept .py but it should be (for fnmatch) *.py etc.: + self.acceptFileExtensions = self.ini.getList('general', 'track file extensions') + self.ignoreFilePatterns = self.ini.getList('general', 'ignore file patterns') + self.filesSections = ['files'] + # from section files (manual): + filesList = self.ini.get('files') + if filesList: + for f in filesList[:]: + filename = self.substituteFilename(self.ini.get('files', f)) + if not os.path.isfile(filename): + print(f'warning _folders, file "{f}" does not exist: "{filename}"') + # self.ini.delete('files', f) + # self.ini.set('obsolete files', f, filename) + continue + self.filesDict[f] = filename + + for trf in self.trackFiles: + if not trf: + continue + trf2 = self.substituteFolder(trf) + if not os.path.isdir(trf2): + print('warning, no valid folder associated with: %s (%s) (skip for track files)'% (trf, trf2)) + continue + filesList = [f for f in os.listdir(trf2) if os.path.isfile(os.path.join(trf2, f))] + self.trackFilesSection = 'files %s'% trf + self.ini.delete(self.trackFoldersSection) # not in inifile + self.filesSections.append(self.trackFilesSection) + for f in filesList: + self.acceptFileInFilesDict(trf, trf2, f) + #self.cleanupIniFilesSection(self.trackFilesSection, trf) + self.removeObsoleteIniSections(prefix="files ", validPostfixes=[]) + #self.removeObsoleteIniSections(prefix="files ", validPostfixes=self.trackFiles) # not in inifile any more + + # self.childBehavesLikeTop = self.ini.getDict('general', 'child behaves like top') + # self.topBehavesLikeChild = self.ini.getDict('general', 'top behaves like child') + # save changes if there were any: + self.ini.writeIfChanged() diff --git a/src/unimacro/UnimacroGrammars/_folders.py b/src/unimacro/UnimacroGrammars/_folders.py index 1f2780d..bf0fdbb 100644 --- a/src/unimacro/UnimacroGrammars/_folders.py +++ b/src/unimacro/UnimacroGrammars/_folders.py @@ -6,8 +6,10 @@ # grammar: _folders.py # Written by: Quintijn Hoogenboom (QH softwaretraining & advies) # starting 2003, revised QH march 2011 -# moved to the GitHub/Dictation-toolbox April 2020 -"""with this grammar, you can reach folders, files and websites from any window. +# moved to the GitHub/Dictation-toolbox April 2020, improved vastly Febr 2024 (with partly new options) +#pylint:disable=C0302, W0613, W0702, R0911, R0912, R0913, R0914, R0915, W0212, W0703 +#pylint:disable=E1101, C0209 +r"""with this grammar, you can reach folders, files and websites from any window. From some windows (my computer and most dialog windows) the folders and files can be called directly by name if they are in the foreground. @@ -20,11 +22,8 @@ This grammar now makes use of ini files, to show and edit the contents of the lists used. -Several "meta actions" are used, eg << # f = r'C:\Documenten\Quintijn' - # remote = r'C:\DocumentenOud' - # print getValidPath(f, remote) -nameenter>> and <> when entering were exiting the file name text box in a file +Several "meta actions" are used, eg <> and <> +when entering were exiting the file name text box in a file dialog. These actions can be tailored for specific programs, like some office programmes to behave different, or for WinZip. See examples in actions.ini (call with "Edit Actions"/"Bewerk acties") @@ -32,73 +31,58 @@ In the inifile also the commands for start this computer or start windows explorer must be given. Correct these commands ("Edit Folders"/"Bewerk folders") if they do not work correct. -New feature: if you want to use xxexplorer (can be used hands-free very -easy, look in https://www.netez.com/xxExplorer), in section [general] -you can put a variable -xxexplorer = path to exe or false ('') This explorer is then taken if you are in or if Explorer is explicitly asked for. The strategy for "New" and "Explorer" (when you say "new", "nieuw", "explorer" in the folder command, are complicated, look below -The site part is only used if you enter a valid folder in siteRoot below. -With this command you can quickly enter a complicated set of there we go agains. - -The subversion additional commands are removed - -The git additional commands are only valid if you specify a valid git client in the ini file general section -(git executable) (I (Quintijn) take git, although I use TortoiseGit manually) - """ -import types import re -import copy -import natlink import pickle #recentfoldersDict -import nsformat # for "remember as" import os import sys import time import fnmatch -import collections -import win32gui -import win32con -from win32com.client import Dispatch -from pprint import pprint -import pywintypes -import inivars # for IniError -import utilsqh -from pathqh import path -import readwritefile -import messagefunctions as mess -import natlinkclipboard -#, win32com -import natlinkcorefunctions # getExtendedEnv -from actions import doAction as action -from actions import doKeystroke as keystroke -from pathqh import getValidPath -from actions import do_YESNO as YesNo -from actions import Message, UnimacroBringUp -import actions -from unimacro_wxpythondialogs import InputBox - -thisDir = (path(__file__)).split()[0] - -import webbrowser import urllib.request import urllib.parse import urllib.error -natut = __import__('natlinkutils') -natqh = __import__('natlinkutilsqh') -natbj = __import__('natlinkutilsbj') +import ctypes # get window text +from pathlib import Path +# from pprint import pprint +from io import StringIO +from logging import getLogger +import win32gui +from win32com.client import Dispatch +import win32clipboard +import natlink +from natlinkcore import readwritefile +from natlinkcore import natlinktimer +from natlinkcore import natlinkstatus +from dtactions.unimacro import extenvvars +from dtactions import messagefunctions as mess +from dtactions import natlinkclipboard +from dtactions.unimacro.unimacroactions import doAction as action +from dtactions.unimacro.unimacroactions import doKeystroke as keystroke +# from dtactions.unimacro.unimacroactions import do_YESNO as YesNo +from dtactions.unimacro.unimacroactions import UnimacroBringUp +from dtactions.unimacro.unimacroactions import Message +from dtactions.unimacro import unimacroutils +# from dtactions.unimacro.unimacroactions import Message +# from dtactions.unimacro import unimacroactions as actions +from unimacro import natlinkutilsbj as natbj +# from unimacro.unimacro_wxpythondialogs import InputBox +# import natlinkcore.natlinkutils as natut + +# manipulating file names with env variables etc... +envvars = extenvvars.ExtEnvVars() +thisDir = str(Path(__file__).parent) +status = natlinkstatus.NatlinkStatus() # for getting unicode explorer window titles: -import ctypes GetWindowText = ctypes.windll.user32.GetWindowTextW GetWindowTextLength = ctypes.windll.user32.GetWindowTextLengthW -import win32clipboard # for substituting environment variable like %HOME% in a file path: # and %DESKTOP% in a file path. @@ -113,28 +97,35 @@ # classes for this computer and windows explorer: Classes = ('ExploreWClass', 'CabinetWClass') -# extra for sites (QH) -try: - siteRoot = getValidPath('(C|D):\\projects\\sitegen') -except IOError: - siteRoot = None -if siteRoot: - siteRoot = siteRoot.normpath() - print("grammar _folder: do specific site commands (QH private)") - if not siteRoot in sys.path: - print('append to sys.path: %s'% siteRoot) - sys.path.append(siteRoot) - # together with track folders history: -doRecentFolderCommand = True # some child windows have to behave as top window (specified in ini file): # note: title is converted to lowercase, only full title is recognised ancestor = natbj.IniGrammar + +#note this is basically copy & pasted into ThisGrammar +#some global scope functions need the same logger. +def logger_name(): + "natlink.unimacro.folders" + +logger = getLogger(logger_name()) + +#logger should be used instead of print +#replace print to avoid unintended use. +builtin_print=print +def our_print(*args,**kwargs): + f=StringIO() + builtin_print(args,kwargs,file=f) + value=f.getvalue() + logger.debug("print called instead of logging functions: %s", value) + logger.error(value) + + class ThisGrammar(ancestor): """grammar for quickly going to folders, files and websites - """ - language = natqh.getLanguage() + """ + #pylint:disable=R0902, R0904, C0116, W0201 + language = unimacroutils.getLanguage() name = "folders" iniIgnoreGrammarLists = ['subfolders', 'subfiles'] # 'recentfolders' is filled via self.in inicngingData @@ -143,11 +134,9 @@ class ThisGrammar(ancestor): # commands with special status, must correspond to a right hand side # of a ini file entry (section foldercommands or filecommands) # remote, openwith have hardcoded details. - optionalfoldercommands = ['new', 'explorer', 'paste', 'copy', 'remote', 'git'] - optionalfilecommands = ['copy', 'paste', 'edit', 'paste', 'remote', 'openwith', 'git'] + optionalfoldercommands = ['new', 'explorer', 'paste', 'copy', 'remote'] + optionalfilecommands = ['copy', 'paste', 'edit', 'paste', 'remote', 'openwith'] - # only used if siteRoot is a valid folder - optionalsitecommands = ['input', 'output', 'local', 'online'] gramSpec = """ exported = folder ({folders}[]); @@ -155,84 +144,78 @@ class ThisGrammar(ancestor): exported = drive {letters} []; exported = ((this|here) folder) (|); = new | here | paste | on ({letters}|{virtualdrivesspoken}) | - (git) {gitfoldercommands}| | {foldercommands}; exported = folder up|folder up {n1-10}; - exported = file ({files}|{subfiles})[|]; # add dot {extensions} later again + exported = recent [folder] ({recentfolders}|SHOW|HIDE|RESET|START|STOP) []; + + exported = file ({files}|{subfiles})[|]; exported = ((here|this) file) (|); = {filecommands}| on ({letters}|{virtualdrivesspoken}) | - ('open with') {fileopenprograms}| - (git) {gitfilecommands}| - ; + ('open with') {fileopenprograms}|; exported = website {websites} []; exported = (this website) (|); = ('open with') {websiteopenprograms}| ; - = remember; + = remember; = (copy (name|path)) | ((name|path) copy); -## set all environment variables into the folders list... - exported = set environment folders; """ - # specific part in use by Quintijn: - if siteRoot: - print('extend grammar with site specific (QH private) commands') - gramSpec = gramSpec + """ - exported = site ({sites}|{sites} ); - exported = site ; - = {sitecommands} | {sitecommands} (|) | - | ; - """ - if doRecentFolderCommand: - gramSpec += """ exported = recent [folder] ({recentfolders}|SHOW|HIDE|RESET|START|STOP) [];""" - def initialize(self): - self.envDict = natlinkcorefunctions.getAllFolderEnvironmentVariables() # for (generalised) environment variables - self.subfiles = self.subfiles = self.activeFolder = None # for catching on the fly in explorer windows (CabinetClassW) + # self.envDict = natlinkcorefunctions.getAllFolderEnvironmentVariables() # for (generalised) environment variables + self.subfiles = self.subfiles = self.activeFolder = self.activeTimerFolder = None # for catching on the fly in explorer windows (CabinetClassW) self.className = None self.dialogWindowTitle = "" # for recent folders dialog, grammar in natspeak.py self.dialogNumberRange = [] # ditto self.catchRemember = "" - self.activeFolder = None - self.previousDisplayRecentFolders = None # displaying recent folders list + self.inTimerRecentFolders = False + self.prevActiveFolder = None + self.subfoldersDict = {} + self.subfilesDict = {} + self.foldersSet = set() + + if not self.language: - print("no valid language in grammar "+__name__+" grammar not initialized") + self.error("no valid language in grammar "+__name__+" grammar not initialized") return self.load(self.gramSpec) - self.lastSite = None self.switchOnOrOff() # initialises lists from inifile, and switches on + def loggerName(self) ->str: + """Returns the name of a logger. Replace this and loggerShortName to create a logger for an inherited grammar. """ + return "natlink.unimacro.folders" + + def loggerShortName(self) ->str: + """A key for use as a spoken form or user interface item. """ + return "folders" + def gotBegin(self,moduleInfo): if self.checkForChanges: self.checkInifile() # refills grammar lists and instance variables # if something changed. - if type(self.checkForChanges) == int and self.checkForChanges > 0: + if isinstance(self.checkForChanges, int) and self.checkForChanges > 0: self.checkForChanges -= 1 if self.mayBeSwitchedOn == 'exclusive': - print("exclusive (_folders), do switchOnOrOff") + self.info("exclusive (_folders), do switchOnOrOff") self.switchOnOrOff() - hndle = moduleInfo[2] - try: - className = win32gui.GetClassName(hndle) - except pywintypes.error as details: - print("no classname found") - className = "" - activeFolder = self.getActiveFolder(hndle, className) - if self.trackAutoFiles or self.trackAutoFolders: - activeFolder = self.getActiveFolder(hndle, className) - if activeFolder: - self.handleTrackFilesAndFolders(activeFolder) - - if hndle and self.trackFoldersHistory: - self.catchTimerRecentFolders(hndle) + self.progInfo = unimacroutils.getProgInfo() + + hndle = self.progInfo.hndle + classname = self.progInfo.classname + # activeFolder = self.getActiveFolder(hndle, classname) + if self.trackFilesAtUtterance or self.trackSubfoldersAtUtterance: + activeFolder = self.getActiveFolder(hndle, classname) + self.handleTrackFilesAndFolders(activeFolder) + + if hndle and self.trackRecentFoldersAtUtterance: + self.catchTimerRecentFolders(hndle, classname) def gotResultsInit(self,words,fullResults): if self.mayBeSwitchedOn == 'exclusive': - print('recog folders, switch off mic') + self.info('recog folders, switch off mic') natbj.SetMic('off') self.wantedFolder = self.wantedFile = self.wantedWebsite = None self.catchRemember = None @@ -241,28 +224,35 @@ def gotResultsInit(self,words,fullResults): # folder options: # CopyName and PasteName refers to the folder, file or website name # Cut, Copy Paste of file or folder is not implemented - self.New = self.Here = self.Remote = self.Git = self.Cut = self.Copy = self.Paste = self.CopyNamePath = self.PastePath = False + self.New = self.Here = self.Remote = self.Cut = self.Copy = self.Paste = self.CopyNamePath = self.PastePath = False # file options: # OpenWith goes via Open. self.Open = self.Edit = None self.FolderOptions = [] self.FileOptions = [] self.WebsiteOptions = [] + # redo getProgInfo, in case the focus did change: + self.progInfo = unimacroutils.getProgInfo() + + def handleTrackFilesAndFolders(self, activeFolder): """set or empty lists for activeFolder and set/reset self.activeFolder """ if self.activeFolder == activeFolder: return + if self.activeFolder: self.emptyListsForActiveFolder() - # print 'empty lists for active folder %s, now: %s'% (self.activeFolder, activeFolder) + self.debug('empty lists for active folder %s, now: %s',self.activeFolder, activeFolder) self.activeFolder = None if activeFolder and os.path.isdir(activeFolder): self.fillListsForActiveFolder(activeFolder) - print('set %s (sub)files and %s subfolders'% (len(self.subfilesDict), len(self.subfoldersDict))) - + # nFiles, nFolders = len(self.subfilesDict), len(self.subfoldersDict) + # print(f'set {nFiles} (sub)files and {nFolders} subfolders') + self.activeFolder = activeFolder + return def fillList(self, listName): """fill a list in the grammar from the data of the inifile @@ -270,37 +260,23 @@ def fillList(self, listName): overload, because the list sites is special:reversed the section [site] must exist,on the right side is to spoken form. """ - #print 'fill list', listName - if listName == 'sites': - if not siteRoot: - print('sites rules ignored') - self.emptyList(listName) - return # skip the site part - self.sitesDict = self.getListOfSites(siteRoot) - items = list(self.sitesDict.keys()) - self.setList(listName, items) - self.ini.writeIfChanged() - self.sitesInstances = {} # to be filled with instance of a site - return items - - elif listName == 'folders': + + if listName == 'folders': if self.foldersDict: items = list(self.foldersDict.keys()) self.foldersSet = { self.substituteFolder(f) for f in self.foldersDict.values()} # print("foldersSet: %s"% self.foldersSet) self.setList('folders', items) return items - else: - print('no folders to set list to') - self.emptyList('folders') + self.info('no folders to set list to') + self.emptyList('folders') elif listName == 'subfolders': if self.subfoldersDict: items = list(self.subfoldersDict.keys()) self.setList('subfolders', items) return items - else: - print('no subfolders to set list to') - self.emptyList('subfolders') + self.info('no subfolders to set list to') + self.emptyList('subfolders') elif listName == 'files': if self.filesDict: @@ -308,92 +284,99 @@ def fillList(self, listName): self.setList('files', items) return items elif listName == 'recentfolders': + self.loadRecentFoldersDict() if self.recentfoldersDict: items = list(self.recentfoldersDict.keys()) self.setList('recentfolders', items) return items - else: - print('no recentfolders in iniChangingData.ini') - self.emptyList('recentfolders') - - elif listName in ['gitfilecommands', 'gitfoldercommands']: - if self.doGit: - return ancestor.fillList(self, listName) - else: - self.emptyList(listName) + self.emptyList('recentfolders') else: return ancestor.fillList(self, listName) + return None def dumpRecentFoldersDict(self): """for making the dict of recent folders persistent """ - dumpToPickle(self.recentfoldersDict, self.pickleChangingData) + if self.pickleChangingData: + dumpToPickle(self.recentfoldersDict, self.pickleChangingData) + else: + self.info('dumpRecentFoldersDict, no self.pickleChangingData') def loadRecentFoldersDict(self): """for getting the dict of recent folders from previous session """ - result = loadFromPickle(self.pickleChangingData) - if result and type(result) is dict: - return result - else: - return {} - - - + if self.pickleChangingData and Path(self.pickleChangingData).is_file(): + result = loadFromPickle(str(self.pickleChangingData)) + if result and isinstance(result, dict): + self.recentfoldersDict = result + return + self.info('no recent folders dict') + self.recentfoldersDict = {} def fillInstanceVariables(self): """fills the necessary instance variables take the lists of folders, virtualdrives (optional) and remotedrives (optional). """ - self.citrixApps = self.ini.getList('general', 'citrix apps') - if self.citrixApps: - print('_folders does special action for citrixApps: %s'% self.citrixApps) - self.xxExplorer = self.ini.get('general', '2xexplorer') + # valid options, value possibly corresponding to an previous option text + optionsdict = {} + optionsdict['initial on'] = '' + optionsdict['child behaves like top'] = '' + + actualoptions = set(self.ini.get('general')) + + self.useOtherExplorer = self.ini.get('general', 'use other explorer') + optionsdict['use other explorer'] = '' if self.useOtherExplorer: if os.path.isfile(self.useOtherExplorer): - print('_folders, use as default explorer: "%s"'% self.useOtherExplorer) + self.info('_folders, use as default explorer: "%s"', self.useOtherExplorer) else: - print('_folders, variable "use other explorer" set to: "%s" (use data from "actions.ini")'% self.useOtherExplorer) + self.info('_folders, variable "use other explorer" set to: "%s" (use data from "actions.ini")' , self.useOtherExplorer) + + # these are for automatic tracking the current folder at an utterance: + optionsdict['track files at utterance'] = 'automatic track files' + optionsdict['track subfolders at utterance'] = 'automatic track folders' + self.trackSubfoldersAtUtterance = self.ini.getInt('general', 'track subfolders at utterance', 0) + self.trackFilesAtUtterance = self.ini.getInt('general', 'track files at utterance', 0) + optionsdict['track recent folders at utterance'] = '' + optionsdict['max recent folders'] = '' + # track recent folder at gotbegin or with timer: ## callback time in seconds: - interval = self.ini.getFloat('general', 'track folders interval') - if interval: - self.trackFoldersInterval = int(interval*1000) # give in seconds - else: - self.trackFoldersInterval = 4000 # default 5 seconds - + optionsdict['timer track folders interval'] = '' + interval = self.ini.getInt('general', 'timer track folders interval', 0) # default 0 (off). + if interval and interval > 100: + self.warning(f'_folders, warning, "timer track folders interval" should be set in seconds, not {interval}') + interval = 0 + self.trackFoldersTimerInterval = int(interval*1000) # give in seconds self.recentfoldersDict = {} - inipath = self.ini.getFilename() - if inipath.endswith('.ini'): - changingDataIniPath = inipath.replace(".ini", "changingdata.pickle") - self.pickleChangingData = inipath.replace(".ini", "changingdata.pickle") - else: - self.pickleChangingData = "" - - ## automatic tracking of recent folders : - self.trackFoldersHistory = self.ini.getInt('general', 'track folders history') - if self.trackFoldersHistory: - if self.pickleChangingData: - self.recentfoldersDict = self.loadRecentFoldersDict() - if self.recentfoldersDict: - print("recentfolders, set %s keys from _folderschangingdata.pickle"% len(self.recentfoldersDict)) - else: - print("recentfolder, no previous recentfolders cached in _folderschangingdata.pickle") - self.doTrackFoldersHistory = True # can be started or stopped with command + self.trackRecentFoldersAtUtterance = self.ini.getBool('general', 'track recent folders at utterance') + self.maxRecentFolders = 0 + + self.pickleChangingData = str(Path(status.getUnimacroDataDirectory())/"recentfoldersdata.pickle") + if self.trackFoldersTimerInterval or self.trackRecentFoldersAtUtterance: + + optionsdict['max recent folders'] = '' + self.maxRecentFolders = self.ini.getInt('general', 'max recent folders', 50) + self.doTrackRecentFolders = True # can be started or stopped with command # recent [folders] START or recent [folders] STOP - intervalSeconds = self.trackFoldersInterval/1000 - print('maintain a list of %s recent folders (Explorer or File Dialog) at every utterance and every %s seconds'% (self.trackFoldersHistory, intervalSeconds)) - natlink.setTimerCallback(self.catchTimerRecentFolders, self.trackFoldersInterval) # every 5 seconds + intervalSeconds = int(self.trackFoldersTimerInterval/1000) + if self.trackFoldersTimerInterval or self.trackRecentFoldersAtUtterance: + if not self.trackFoldersTimerInterval: + track_message=f'maintain a list of (max) {self.maxRecentFolders} recent folders (Explorer or File Dialog) at every utterance' + elif not self.trackRecentFoldersAtUtterance: + track_message=f'maintain a list of (max) {self.maxRecentFolders} recent folders (Explorer or File Dialog) every {intervalSeconds} seconds' + else: + track_message=f'maintain a list of (max) {self.maxRecentFolders} recent folders (Explorer or File Dialog) at every utterance and every {intervalSeconds} seconds' + self.info(track_message) + if self.trackFoldersTimerInterval: + natlinktimer.setTimerCallback(self.catchTimerRecentFolders, self.trackFoldersTimerInterval) # every 5 seconds default... else: - self.doTrackFoldersHistory = False - if self.doTrackFoldersHistory: - rfList = self.ini.get('recentfolders') - for key in rfList: - value = self.ini.get('recentfolders', key) - self.recentfoldersDict[key] = value + self.doTrackRecentFolders = False + + # virtual drives: # extract special variables from ini file: self.virtualDriveDict = {} wantedVirtualDriveList = self.ini.get('virtualdrives') @@ -407,39 +390,29 @@ def fillInstanceVariables(self): foldersList = self.ini.get('folders') self.foldersDict = {} for f in foldersList: - folder = self.substituteFolder(self.ini.get('folders', f)) + raw_folder = self.ini.get('folders', f) + folder = self.substituteFolder(raw_folder) if not os.path.isdir(folder): - print(f'warning _folders, folder "{f}" does not exist: "{folder}"') + self.warning(f'warning _folders, folder "{f}" does not exist: "{folder}"') # self.ini.delete('folders', f) # self.ini.set('obsolete folders', f, folder) continue self.foldersDict[f] = folder # track virtual drives if in ini file: + optionsdict['track folders virtualdrives'] = '' + optionsdict['track files virtualdrives'] = '' self.trackFolders = self.ini.getList('general', 'track folders virtualdrives') self.trackFiles = self.ini.getList('general', 'track files virtualdrives') - # below this threshold, the getting of subfolders and files in a directory is not printed in the messages window - self.notifyThresholdMilliseconds = self.ini.getInt("general", "notify threshold milliseconds", 10) - print("_folders, notify threshold milliseconds: %s"% self.notifyThresholdMilliseconds) - # in order to accept .py but it should be (for fnmatch) *.py etc.: + + # in order to accept files in the list but it should be (for fnmatch) *.py etc.: + optionsdict['track file extensions'] = '' + optionsdict['ignore file patterns'] = '' + self.acceptFileExtensions = self.ini.getList('general', 'track file extensions') self.ignoreFilePatterns = self.ini.getList('general', 'ignore file patterns') - # these are for automatic tracking the current folder: - self.trackAutoFolders = self.ini.getBool('general', 'automatic track folders') - self.trackAutoFiles = self.ini.getBool('general', 'automatic track files') - windowsVersion = natqh.getWindowsVersion() - if (self.trackAutoFiles or self.trackAutoFolders) and windowsVersion in ('XP', '2000', 'NT4', 'NT351', '98'): - print('_folders: the options for "automatic track files" and "automatic track folders" of a directory probably do not work for this Windows version: %s'% windowsVersion) - self.doGit = self.ini.get('general', 'git executable') - if self.doGit: - if not os.path.isfile(self.doGit): - print('not a valid path to git executable: %s, ignore'% self.doGit) - self.doGit = None - if not self.doGit: - self.iniIgnoreGrammarLists.extend(['gitfoldercommands', 'gitfilecommands']) - self.foldersSections = ['folders'] # track folders: for trf in self.trackFolders: @@ -448,7 +421,7 @@ def fillInstanceVariables(self): trf2 = self.substituteFolder(trf) #print 'input: %s, output: %s'% (trf, trf2) if not os.path.isdir(trf2): - print('warning, no valid folder associated with: %s (%s) (skip for track virtualdrives)'% (trf, trf2)) + self.warning('warning, no valid folder associated with: %s (%s) (skip for track virtualdrives)', trf, trf2) continue #else: # print 'valid folder for tracking: %s (%s)'% (trf, trf2) @@ -468,26 +441,25 @@ def fillInstanceVariables(self): self.filesDict = {} self.trackFiles = self.ini.getList('general', 'track files virtualdrives') # in order to accept .py but it should be (for fnmatch) *.py etc.: - self.acceptFileExtensions = self.ini.getList('general', 'track file extensions') - self.ignoreFilePatterns = self.ini.getList('general', 'ignore file patterns') self.filesSections = ['files'] # from section files (manual): filesList = self.ini.get('files') - for f in filesList[:]: - filename = self.substituteFilename(self.ini.get('files', f)) - if not os.path.isfile(filename): - print(f'warning _folders, file "{f}" does not exist: "{filename}"'% (f, filename)) - # self.ini.delete('files', f) - # self.ini.set('obsolete files', f, filename) - continue - self.filesDict[f] = filename + if filesList: + for f in filesList[:]: + filename = self.substituteFilename(self.ini.get('files', f)) + if not os.path.isfile(filename): + self.warning(f'warning _folders, file "{f}" does not exist: "{filename}"') + # self.ini.delete('files', f) + # self.ini.set('obsolete files', f, filename) + continue + self.filesDict[f] = filename for trf in self.trackFiles: if not trf: continue trf2 = self.substituteFolder(trf) if not os.path.isdir(trf2): - print('warning, no valid folder associated with: %s (%s) (skip for track files)'% (trf, trf2)) + self.warning('warning, no valid folder associated with: %s (%s) (skip for track files)', trf, trf2) continue filesList = [f for f in os.listdir(trf2) if os.path.isfile(os.path.join(trf2, f))] self.trackFilesSection = 'files %s'% trf @@ -502,21 +474,42 @@ def fillInstanceVariables(self): # self.childBehavesLikeTop = self.ini.getDict('general', 'child behaves like top') # self.topBehavesLikeChild = self.ini.getDict('general', 'top behaves like child') # save changes if there were any: - self.ini.writeIfChanged() + self.ini.writeIfChanged() + + self.checkValidOptions(optionsdict, actualoptions) + def checkValidOptions(self, optionsdict, actualoptions): + """check if all options given are valid and give feedback + """ + validoptions = set(optionsdict) + oldoptions = actualoptions - validoptions + if oldoptions: + self.info(f'obsolete options: {oldoptions}') + # give new option, if available: + for old in oldoptions: + for k,v in optionsdict.items(): + if v == old: + self.info(f'replace option "{old}" into "{k}" please') + break + unusedoptions = validoptions - actualoptions + for unused in unusedoptions: + self.warning(f'-- option "{unused}" is not set, grammar "_folders",\n\tplease set (possibly without value) in section [general]') - def fillGrammarLists(self, listOfLists=None, ignoreFromIni='general', - ignoreFromGrammar=None): + def fillGrammarLists(self, listOfLists=None): """fills the lists of the grammar with data from inifile - extra, the 'recentfolders' list from iniChangingData!! + extra, the 'recentfolders' list in self.loadRecentFoldersDict (note: fillList is a specialised function of this grammar) """ ancestor.fillGrammarLists(self) ## this one is ignored in the` parent class version of this function - self.fillList('recentfolders') + ## when recentfolders is not needed in the grammar, it raises a ValueError + try: + self.fillList('recentfolders') + except ValueError: + pass def resolveVirtualDrives(self, wantedVirtualDrives): """check the virtual drives, possibly recursive @@ -527,7 +520,8 @@ def resolveVirtualDrives(self, wantedVirtualDrives): no return, self.virtualDriveDict is filled. if no progress, make the remaining virtual drives obsolete... """ - if not wantedVirtualDrives: return ## nothing done + if not wantedVirtualDrives: + return ## nothing done lenPrevious = 0 #checking the paths of virtualDriveList: while wantedVirtualDrives and lenPrevious != len(wantedVirtualDrives): @@ -544,7 +538,7 @@ def resolveVirtualDrives(self, wantedVirtualDrives): if wantedVirtualDrives: textline = ", ".join(wantedVirtualDrives) - print(f'Warning: could not resolve "virtualdrive" entries: {textline}, ignore') + self.warning(f'Warning: could not resolve "virtualdrive" entries: {textline}, ignore') # for dr in wantedVirtualDrives: # virtualDrive = self.ini.get('virtualdrives', dr) # self.ini.delete('virtualdrives', dr) @@ -556,12 +550,12 @@ def getFolderFromVirtualDrive(self, vd): also make alternative paths possible like (C|D):/Documents """ # natlinkcorefunctions.printAllEnvVariables() - vd = natlinkcorefunctions.expandEnvVariables(vd) + vd = envvars.expandEnvVariables(vd) for possiblePath in loop_through_alternative_paths(vd): folder = self.substituteFolder(possiblePath) if os.path.isdir(folder): return os.path.normpath(folder) - + return None def acceptVirtualDrivesFolder(self, vd, realfolder, foldername=None): """check validity of virtualdrive subfolder and put or remove from inifile @@ -607,91 +601,92 @@ def getActiveFolder(self, hndle=None, className=None): hndle = curmod[2] if not hndle: # print("getActiveFolder, not a foreground hndle found: %s"% hndle) - return - if className is None: + return None + try: className = win32gui.GetClassName(hndle) - # print 'getActiveFolder, className: %s'% className - if not className: return + except Exception as e: + if e.args[0] == 1400: + print(f'exception: {e}') + else: + print(f'unexpected exception: {e}') + return None + + if not className: + return None f = None if className == "CabinetWClass": f = mess.getFolderFromCabinetWClass(hndle) - # if f and f.startswith("search-ms"): - # keystroke("{esc}") - # natqh.Wait() - # f = mess.getFolderFromDialog(hndle, className) - if not f: - print("getActiveFolder, CabinetWClass failed: %s"% hndle) elif className == '#32770': f = mess.getFolderFromDialog(hndle, className) - if not f: - return - # if not f: - # print "getActiveFolder, #32770 failed: %s"% hndle - else: - # print 'class for activeFolder: %s'% className - return if not f: - if className == 'CabinetWClass': - print('_folders, getActiveFolder, no folder found in className %s'% className) - return + self.prevActiveFolder = f + return None if os.path.isdir(f): nf = os.path.normpath(f) - # print("getActiveFolder: %s"% nf) + if nf != self.prevActiveFolder: + self.debug("getActiveFolder, got: %s",nf) + self.prevActiveFolder = nf return nf - # print("folder in getActiveFolder: %s"% f) - realFolder = natlinkcorefunctions.getFolderFromLibraryName(f) - if realFolder: - # print("getActiveFolder realFolder for %s: %s"% (f, realFolder)) - return realFolder - print('_folders, getActiveFolder, could not find folder for %s'% f) - + result = envvars.getFolderFromLibraryName(f) + if result and os.path.isdir(result): + self.debug("getActiveFolder, via getFolderFromLibraryName %s: %s", f, result) + return os.path.normpath(result) + self.warning('getActiveFolder, strange invalid path for folder: %s', f) + return None + def fillListsForActiveFolder(self, activeFolder): """fill list of files and subfolders also set activeFolder and className this is for the automatic filling of the active window (either explorer, CabinetWClass, or child #32770. - - Seems to fail in windows XP and before. - + """ subs = os.listdir(activeFolder) # print 'subs: %s'% subs subfolders = [s for s in subs if os.path.isdir(os.path.join(activeFolder, s))] subfiles = [s for s in subs if os.path.isfile(os.path.join(activeFolder, s))] - self.subfoldersDict = self.getSpokenFormsDict(subfolders) - self.subfilesDict = self.getSpokenFormsDict(subfiles, extensions=1) + if self.trackFilesAtUtterance: + if len(subfiles) > self.trackFilesAtUtterance: + self.info(f'_folders, only set first {self.trackFilesAtUtterance} files, total: {len(subfiles)}') + subfiles = subfiles[:self.trackFilesAtUtterance] + self.subfilesDict = self.getSpokenFormsDict(subfiles, extensions=1) + else: + self.subfilesDict = {} + + if self.trackSubfoldersAtUtterance: + if len(subfolders) > self.trackSubfoldersAtUtterance: + self.info(f'_folders, only set first {self.trackSubfoldersAtUtterance} subfolders of total: {len(subfolders)}') + subfolders = subfolders[:self.trackSubfoldersAtUtterance] + self.subfoldersDict = self.getSpokenFormsDict(subfolders) + else: + self.subfoldersDict = {} + # print 'activeFolder, %s, subfolders: %s'% (activeFolder, self.subfoldersDict.keys()) # print 'activeFolder, %s, subfiles: %s'% (activeFolder, self.subfilesDict.keys()) # print 'activeFolder, %s, subfiles: %s'% (activeFolder, self.subfilesDict) - if self.trackAutoFiles and self.subfilesDict: + if self.subfilesDict: self.setList('subfiles', list(self.subfilesDict.keys())) - if self.trackAutoFolders and self.subfoldersDict: - n0 = time.time() + if self.subfoldersDict: self.setList('subfolders', list(self.subfoldersDict.keys())) - n1 = time.time() - elapsed = int((n1 - n0)*1000) - if elapsed > self.notifyThresholdMilliseconds: - print('set %s subfolders in %s milliseconds'% (len(list(self.subfoldersDict.keys())), elapsed)) self.activeFolder = activeFolder + if self.subfilesDict and self.subfoldersDict: + self.info(f'activeFolder, set {len(subfiles)} files and {len(subfolders)} subfolders') + elif self.subfilesDict: + self.info(f'activeFolder, set {len(subfiles)} files') + elif self.subfoldersDict: + self.info(f'activeFolder, set {len(subfolders)} subfolders') + def emptyListsForActiveFolder(self): """no sublists, empty """ - n0 = time.time() - lenSubFolders = len(self.subfoldersDict) - lenSubFiles = len(self.subfilesDict) - if self.trackAutoFiles: + if self.trackFilesAtUtterance: self.emptyList('subfiles') self.subfilesDict.clear() - if self.trackAutoFolders: + if self.trackSubfoldersAtUtterance: self.emptyList('subfolders') self.subfoldersDict.clear() - n1 = time.time() - elapsed = int((n1 - n0)*1000) - if elapsed: - # if elapsed > self.notifyThresholdMilliseconds: - print('emptyListsForActiveFolder: emptied %s subfolders and %s (sub)files in %s milliseconds'% (lenSubFolders, lenSubFiles, elapsed)) self.activeFolder = None @@ -704,10 +699,10 @@ def cleanupIniFoldersSection(self, section, vd): continue folder = self.substituteFolder(vd + ':/' + f) if not os.path.isdir(folder): - print('remove entry from ini folders section %s: %s (%s)'% (section, f, folder)) + self.info('remove entry from ini folders section %s: %s (%s)', section, f, folder) self.ini.delete(section, f) elif not self.acceptFileName(f): - print('remove entry from ini folders section %s: %s (%s)(invalid folder name)'% (section, f, folder)) + self.info('remove entry from ini folders section %s: %s (%s)(invalid folder name)' ,section, f, folder) self.ini.delete(section, f) self.ini.writeIfChanged() @@ -718,13 +713,13 @@ def cleanupIniFilesSection(self, section, vd): filename = self.substituteFolder(vd + ':/' + f) trunk, ext = os.path.splitext(f) if not self.acceptExtension(ext): - print('remove entry from ini files section %s: %s (%s)(invalid extension)'% (section, f, filename)) + self.info('remove entry from ini files section %s: %s (%s)(invalid extension)', section, f, filename) self.ini.delete(section, f) elif not self.acceptFileName(trunk): - print('remove entry from ini files section %s: %s (%s)(invalid filename)'% (section, f, filename)) + self.info('remove entry from ini files section %s: %s (%s)(invalid filename)', section, f, filename) self.ini.delete(section, f) elif not os.path.isfile(filename): - print('remove entry from ini files section %s: %s (%s)'% (section, f, filename)) + self.info('remove entry from ini files section %s: %s (%s)', section, f, filename) self.ini.delete(section, f) self.ini.writeIfChanged() @@ -741,7 +736,7 @@ def removeObsoleteIniSections(self, prefix, validPostfixes): if section == prefix + postfix: break else: - print('_folders grammar, deleting ini file section: %s'% section) + self.info('_folders grammar, deleting ini file section: %s', section) self.ini.delete(section) self.ini.writeIfChanged() @@ -769,7 +764,8 @@ def acceptFileInFilesDict(self, vd, realfolder, filename): #except inivars.IniError: # return - if not spoken: return + if not spoken: + return for sp in spoken: self.filesDict[sp] = vd + ':/' + f @@ -780,19 +776,30 @@ def catchTimerRecentFolders(self, hndle=None, className=None): Or with the subfolder or folder ... on virtual drive command. - Whenever there is a folder in the foreground, is is cached as recentfolder. + Whenever there is a folder in the foreground, it is cached as recentfolder. When the buffer grows too large, the first inserted items are removed from the list - (QH, March 2020) + (QH, March 2020, Febr 2024) """ - activeFolder = self.getActiveFolder(hndle, className) - if not activeFolder: return - - # activeFolder = os.path.normcase(activeFolder) - if self.recentfoldersDict and activeFolder == list(self.recentfoldersDict.values())[-1]: + # print('_folders, catchTimerRecentFolders') + if self.inTimerRecentFolders: return - spokenName = self.getFolderBasenameRemember(activeFolder) - self.manageRecentFolders(spokenName, activeFolder) + self.inTimerRecentFolders = True + try: + activeFolder = self.getActiveFolder(hndle, className) + if not activeFolder: + return + if activeFolder == self.activeTimerFolder: + return + self.activeTimerFolder = activeFolder + # activeFolder = os.path.normcase(activeFolder) + if self.recentfoldersDict and activeFolder == list(self.recentfoldersDict.values())[-1]: + return + spokenName = self.getFolderBasenameRemember(activeFolder) + # print(f'add activeFolder "{activeFolder}" to recent, spoken name: "{spokenName}"') + self.manageRecentFolders(spokenName, activeFolder) + finally: + self.inTimerRecentFolders = False def manageRecentFolders(self, Spoken, Folder): """manage the internals of the recent folders dict @@ -801,37 +808,33 @@ def manageRecentFolders(self, Spoken, Folder): Or from the subfolder or folder ... on virtual drive commands """ # first see if the buffer needs to be shrinked: - buffer = max(10, self.trackFoldersHistory//10) - if len(self.recentfoldersDict) > self.trackFoldersHistory + buffer: - print("shrink recentfoldersDict with %s items to %s"% (buffer, self.trackFoldersHistory)) - while len(self.recentfoldersDict) >= self.trackFoldersHistory: - keysList = list(self.recentfoldersDict.keys()) - removeItem = self.recentfoldersDict.pop(keysList[0]) - # print('_folders, remove from recent folders: %s (%s)'% (keysList[0], removeItem)) - # print("refilling recentfolders list with %s items'"% len(self.recentfoldersDict)) - self.setList('recentfolders', list(self.recentfoldersDict.keys())) - self.dumpRecentFoldersDict() - # self.pickleChangingData.delete('recentfolders') - # for key, value in self.recentfoldersDict.items(): - # # self.pickleChangingData.set("recentfolders", key, value) - # self.pickleChangingData.writeIfChanged() + buffer = max(10, self.maxRecentFolders//10) + self.info(f'manageRecentFolders buffer: {buffer}, self.maxRecentFolders: {self.maxRecentFolders}, len(recentfoldersDict): {len(self.recentfoldersDict)}') + if self.recentfoldersDict: + if len(self.recentfoldersDict) > self.maxRecentFolders + buffer: + self.info("shrink recentfoldersDict with %s items to %s", buffer, self.maxRecentFolders) + while len(self.recentfoldersDict) >= self.maxRecentFolders: + keysList = list(self.recentfoldersDict.keys()) + _removeItem = self.recentfoldersDict.pop(keysList[0]) + # print('_folders, remove from recent folders: %s (%s)'% (keysList[0], removeItem)) + # print("refilling recentfolders list with %s items'"% len(self.recentfoldersDict)) + self.setList('recentfolders', list(self.recentfoldersDict.keys())) + self.dumpRecentFoldersDict() - if not Spoken: return + if not Spoken: + return if Spoken in self.recentfoldersDict: spokenFolder = self.recentfoldersDict[Spoken] if spokenFolder == Folder: + self.info(f'readd {Spoken} to recentfoldersDict') del self.recentfoldersDict[Spoken] self.recentfoldersDict[Spoken] = Folder self.dumpRecentFoldersDict() - # self.pickleChangingData.set("recentfolders", Spoken, Folder) # print('re-enter Folder in recent folders: %s (%s)'% (Spoken, Folder)) elif Folder not in self.foldersSet: - print('-- "recent [folder] %s": %s\nNote: "folder %s", points to: %s'% (Spoken, Folder, Spoken, spokenFolder)) + # print('-- "recent [folder] %s": %s\nNote: "folder %s", points to: %s'% (Spoken, Folder, Spoken, spokenFolder)) del self.recentfoldersDict[Spoken] self.recentfoldersDict[Spoken] = Folder self.dumpRecentFoldersDict() - ## try to maintain order: - # self.pickleChangingDatahangingData.delete('recentfolders', Spoken) - # self.pickleChangingData.set("recentfolders", Spoken, Folder) else: # print('adding Folder in recent folders: %s (%s)'% (Spoken, Folder)) self.recentfoldersDict[Spoken] = Folder @@ -841,17 +844,25 @@ def manageRecentFolders(self, Spoken, Folder): # self.pickleChangingData.writeIfChanged() def startRecentFolders(self): - self.doTrackFoldersHistory = True + self.doTrackRecentFolders = True self.fillList('recentfolders') - natlink.setTimerCallback(self.catchTimerRecentFolders, self.trackFoldersInterval) # should have milliseconds - print("track folders history is started, the timer callback is on") + timerInterval = self.trackFoldersTimerInterval + if timerInterval: + self.info(f'start timer interval {timerInterval} milliseconds') + else: + timerInterval = 1000 + self.info(f'start timer with interval {timerInterval} milliseconds, for this session only') + natlinktimer.setTimerCallback(self.catchTimerRecentFolders, self.trackFoldersTimerInterval) # should have milliseconds def stopRecentFolders(self): - self.doTrackFoldersHistory = True - natlink.setTimerCallback(self.catchTimerRecentFolders, 0) + self.doTrackRecentFolders = False + natlinktimer.setTimerCallback(self.catchTimerRecentFolders, 0) + self.dumpRecentFoldersDict() self.recentfoldersDict = {} self.emptyList('recentfolders') - print("track folders history is stopped, the timer callback is off") + self.info("the track recent folders timer is stopped, for this session" if self.trackFoldersTimerInterval \ + else "the track recent folders timer is stopped.") + def resetRecentFolders(self): self.recentfoldersDict = {} @@ -859,20 +870,20 @@ def resetRecentFolders(self): # self.pickleChangingData.delete('recentfolders') # self.pickleChangingData.writeIfChanged() self.emptyList('recentfolders') - + def displayRecentFolders(self): """display the list of recent folders """ - mess = ["_folders, recent folders:"] - for name, value in self.recentfoldersDict.items(): - mess.append('- %s: %s'% (name, value)) - mess.append('-'*20) - mess = '\n'.join(mess) - if mess == self.previousDisplayRecentFolders: - print("recent folders, no change") + mess_list = ["--- recent folders:"] + if not self.recentfoldersDict: + message = 'recent folders list is empty at the moment' + self.info(message) return - self.previousDisplayRecentFolders = mess - print(mess) + for name, value in reversed(self.recentfoldersDict.items()): + mess_list.append('- %s: %s'% (name, value)) + mess_list.append('-'*20) + message = '\n'.join(mess_list) + Message(message) # def gotoRecentFolder(self, chooseNum): @@ -882,96 +893,6 @@ def displayRecentFolders(self): # wantedFolder = self.recentfoldersList[chooseNum] # self.gotoFolder(wantedFolder) - def gotResults_siteshort(self,words,fullResults): - """switch to last mentioned site in the list - mainly for private use, a lot of folders reside in the root folder, - siteRoot. They all have an input folder and a output folder. - - - """ - if self.lastSite: - words.insert(1, self.lastSite) - print('lastSite: %s'% words) - self.gotResults_site(words, fullResults) - else: - self.DisplayMessage('no "lastSite" available yet') - - - def gotResults_setenvironmentfolders(self,words,fullResults): - """switch to last mentioned site in the list - mainly for private use, a lot of folders reside in the root folder, - siteRoot. They all have an input folder and a output folder. - - - """ - reverseOldValues = {'ignore': []} - for k in self.ini.get('folders'): - val = self.ini.get('folders', k) - if val: - reverseOldValues.setdefault(val, []).append(k) - else: - reverseOldValues['ignore'].append(k) - reverseVirtualDrives = {} - for k in self.ini.get('virtualdrives'): - val = self.ini.get('virtualdrives', k) - reverseVirtualDrives.setdefault(val, []).append(k) - -## print reverseOldValues - allFolders = self.envDict() # natlinkcorefunctions.getAllFolderEnvironmentVariables() - kandidates = {} - ignore = reverseOldValues['ignore'] - for (k,v) in list(allFolders.items()): - kSpeakable = k.replace("_", " ") - if k in ignore or kSpeakable in ignore: - continue - oldV = self.ini.get('folders', k, "") or self.ini.get('folders', kSpeakable) - if oldV: - vPercented = "%" + k + "%" - if oldV == v: - continue - elif oldV == vPercented: - kPrevious = reverseOldValues[vPercented] -## print 'vPercented: %s, kPrevious: %s'% (vPercented, kPrevious) - if vPercented in reverseOldValues: - if k in kPrevious or kSpeakable in kPrevious: - continue - else: - print('already in there: %s (%s), but spoken form changed to %s'% \ - (k, v, kPrevious)) - continue - else: - print('different for %s: old: %s, new: %s'% (k, oldV, v)) - kandidates[k] = v - count = len(kandidates) - - if not kandidates: - self.DisplayMessage("no new environment variables to put into the folders section") - return - mes = ["%s new environment variables for your folders section of the grammar _folders"% count] - - Keys = list(kandidates.keys()) - Keys.sort() - for k in Keys: - mes.append("%s\t\t%s"% (k, kandidates[k])) - - mes.append('\n\nDo you want these new environment variables in your folders section?') - - - - if YesNo('\n'.join(mes)): - for (k,v) in list(kandidates.items()): - if k.find('_') > 0: - kSpeakable = k.replace("_", " ") - if self.ini.get('folders', k): - self.ini.delete('folders', k) - else: - kSpeakable = k - self.ini.set('folders', kSpeakable, "%" + k + "%") - self.ini.write() - self.DisplayMessage('added %s entries, say "Show|Edit folders" to browse'% count) - else: - self.DisplayMessage('nothing added, command canceled') - def gotResults_website(self,words,fullResults): """start webbrowser, websites in inifile unders [websites] @@ -1002,14 +923,14 @@ def gotResults_thiswebsite(self,words,fullResults): """get current website and open with websitecommands rule """ - natqh.saveClipboard() + unimacroutils.saveClipboard() action('SSK {alt+d}{extend}{shift+exthome}{ctrl+c}') action("VW") - self.wantedWebsite = natqh.getClipboard() + self.wantedWebsite = unimacroutils.getClipboard() self.wantedWebsite = self.wantedWebsite.rstrip("/") self.catchRemember = "website" - print('this website: %s'% self.wantedWebsite) - natqh.restoreClipboard() + self.info('this website: %s', self.wantedWebsite) + unimacroutils.restoreClipboard() if self.hasCommon(words, "remember"): ## dgndictation is not used at the moment!! if self.nextRule == "dgndictation": @@ -1018,11 +939,11 @@ def gotResults_thiswebsite(self,words,fullResults): self.checkForChanges = True spokenWebsite = self.getWebsiteBasenameRemember(self.wantedWebsite) if not spokenWebsite: - print("_folders, could not extract a nice spoken website from %s\nTry "% self.wantedWebsite) - print('Try "this website remember as "') + self.info("_folders, could not extract a nice spoken website from %s\nTry ", self.wantedWebsite) + self.info('Try "this website remember as "') return self.ini.set("websites", spokenWebsite, self.wantedWebsite) - print('with "website %s" you can now open %s'% (spokenWebsite, self.wantedWebsite)) + self.info('with "website %s" you can now open %s', spokenWebsite, self.wantedWebsite) self.ini.write() def getWebsiteBasenameRemember(self, url): @@ -1038,17 +959,13 @@ def getWebsiteBasenameRemember(self, url): def getFileBasenameRemember(self, filePath): """extract the website main from a file path """ - if isinstance(filePath, path): - namePart = filePath.split()[-1] - else: - namePart = os.path.split(filePath)[-1] - namePart = os.path.splitext(namePart)[0] + namePart = Path(filePath).stem spokenList = self.spokenforms.generateMixedListOfSpokenForms(namePart) if not spokenList: return namePart if len(spokenList) > 1: - print('getFileBasenameRemember, more spoken alternatives found: %s, return first item'% spokenList) + self.info('getFileBasenameRemember, more spoken alternatives found: %s, return first item', spokenList) return spokenList[0] # def checkSubfolderRecent(self, name, folder): @@ -1071,8 +988,8 @@ def getFileBasenameRemember(self, filePath): # else: # self.recentfoldersDict[name] = folder # return # no setList needed - - self.setList('recentfolders', list(self.recentfoldersDict.keys())) + ## TODOQH:: + # self.setList('recentfolders', list(self.recentfoldersDict.keys())) def getDuplicateFolders(self, wantedFolder): """get (spoken, folder) list for this wanted folder @@ -1089,26 +1006,19 @@ def getDuplicateFolders(self, wantedFolder): def cleanpath(self, somepath): """normalise path, and lowercase """ - if isinstance(somepath, path): - return str(somepath) - else: - p = path(somepath) - return str(p) + p = str(Path(somepath)) + return p def getFolderBasenameRemember(self, folderPath): """extract the spoken name from the folder path """ - # print('getFolderBasenameRemember, folderPath: %s'% folderPath) - if isinstance(folderPath, path): - namePart = folderPath.split()[-1] - else: - namePart = os.path.split(folderPath)[-1] + folderPath = Path(folderPath) + namePart = folderPath.name spokenList = self.spokenforms.generateMixedListOfSpokenForms(namePart) - # print('namePart: %s, spokenList: %s'% (namePart, spokenList)) if not spokenList: return namePart if len(spokenList) > 1: - print('getFolderBasenameRemember, more spoken alternatives found: %s'% spokenList) + self.info('getFolderBasenameRemember, more spoken alternatives found: %s', spokenList) return spokenList[0] @@ -1120,7 +1030,7 @@ def gotResults_websitecommands(self,words,fullResults): open with list in inifile, expected right hand sides to be browsers """ if not self.wantedWebsite: - print('websitecommands, no valid self.wantedWebsite: %s'% self.wantedWebsite) + self.info('websitecommands, no valid self.wantedWebsite: %s', self.wantedWebsite) nextOpenWith = False @@ -1131,7 +1041,7 @@ def gotResults_websitecommands(self,words,fullResults): self.Open = self.getFromInifile(w, 'websiteopenprograms') nextOpenWith = False else: - print("unexpected website option: %s"% w) + self.warning("unexpected website option: %s", w) def gotResults_subfolder(self, words, fullResults): """collects the given command words and try to find the given subfolder @@ -1145,10 +1055,9 @@ def gotResults_subfolder(self, words, fullResults): if self.activeFolder and folderWord in self.subfoldersDict: subfolder = self.subfoldersDict[folderWord] folder = os.path.join(self.activeFolder, subfolder) - print('subfolder: %s'% folder) else: - print('cannot find subfolder: %s'% folderWord) - print('subfoldersDict: %s'% self.subfoldersDict) + self.info('cannot find subfolder: %s', folderWord) + self.info('subfoldersDict: %s', self.subfoldersDict) return # subfolder = None # folder1 = self.foldersDict[words[1]] @@ -1157,8 +1066,7 @@ def gotResults_subfolder(self, words, fullResults): # if no next rule, simply go: self.wantedFolder = folder self.Here = True - if doRecentFolderCommand: - self.manageRecentFolders(folderWord, folder) + self.manageRecentFolders(folderWord, folder) def gotResults_recentfolder(self,words,fullResults): """give list of recent folders and choose option @@ -1166,147 +1074,24 @@ def gotResults_recentfolder(self,words,fullResults): if self.hasCommon("SHOW", words[-1]): self.displayRecentFolders() return - elif self.hasCommon("RESET", words[-1]): + if self.hasCommon("RESET", words[-1]): self.resetRecentFolders() - print("Reset recent folders list") + self.info("Reset recent folders list") return - elif self.hasCommon("START", words[-1]): + if self.hasCommon("START", words[-1]): self.startRecentFolders() return - elif self.hasCommon("STOP", words[-1]): + if self.hasCommon("STOP", words[-1]): self.stopRecentFolders() return if not self.recentfoldersDict: - print("no recentfolders yet") + self.info("no recentfolders yet") return name = words[-1] folder = self.recentfoldersDict[name] - print("recentfolder, name: %s, folder: %s"% (name, folder)) + self.info("recentfolder, name: %s, folder: %s", name, folder) self.wantedFolder = folder - - def gotResults_site(self,words,fullResults): - """switch to one of the sites in the list - mainly for private use, a lot of folders reside in the root folder, - siteRoot. They all have an input folder and a output folder. - - """ - print('site: %s'% words) - siteSpoken = words[1] - self.lastSite = None # name of site - if siteSpoken in self.sitesDict: - siteName = self.sitesDict[siteSpoken] - self.lastSite = siteName - else: - raise ValueError("no siteName for %s"% siteSpoken) - - self.site = self.getSiteInstance(siteName) - - if siteName in self.sitesInstances: - self.site = self.sitesInstances[siteName] - else: - site = self.getSiteInstance(siteName) - if site: - self.sitesInstances[siteName] = site - self.lastSite = siteName - self.site = site - else: - self.site = None - print('could not get site: %s'% siteName) - # - #if site is None: - # print 'invalid site: %s, marking in ini file'% site - # self.ini.set('sites', siteName, '') - # self.ini.write() - # return - if self.nextRule == 'sitecommands': - print('site %s, waiting for sitecommands'% self.site) - else: - if self.site: - self.wantedFolder = self.site.rootDir - else: - print("_folders, site command (private QH), no site specified") - - def gotResults_sitecommands(self, words, fullResults): - """do the various options for sites (QH special). - Assume lastSite is set - """ - if not self.site: - print("sitecommands, no last or current site set") - return - print('sitecommands for "%s": %s (site: %s)'% (self.lastSite, words, self.site)) - site = self.site - website, folder = None, None - for command in words: - command = self.getFromInifile(words[0], 'sitecommands') - - if command == 'input': - print('input: %s'% words) - folder = str(site.sAbs) - elif command == 'output': - folder = str(site.hAbs) - elif command == 'local': - website = os.path.join(str(site.hAbs), 'index.html') - elif command == 'online': - sitePrefix = site.sitePrefix - if type(sitePrefix) == dict: - for k, v in sitePrefix.items(): - sitePrefix = v - break - - website = os.path.join(str(sitePrefix), 'index.html') - elif command == 'testsite': - if 'sg' in self.sitesInstances: - testsite = self.sitesInstances['sg'] - else: - testsite = self.getSiteInstance('sg') - if testsite: - self.sitesInstances['sg'] = testsite - - if testsite: - # site at sitegen site: - website = os.path.join(str(testsite.sitePrefix['nl']), self.lastSite, 'index.html') - - if self.nextRule: - if folder: - self.wantedFolder = folder - return - elif website: - self.wantedWebsite = website - return - else: - print('no valid folder or website for nextRule') - return - elif folder: - self.gotoFolder(folder) - self.wantedFolder = None - elif website: - self.gotoWebsite(website) - self.wantedWebsite = None - - def getSiteInstance(self, siteName): - """return pageopen function of site instance, or None - """ - try: - site = __import__(siteName) - except ImportError as msg: - import traceback - print('cannot import module %s'% siteName) - print(traceback.print_exc()) - currentDir = '.' in sys.path - print('currentDir in sys.path: %s'% currentDir) - print('sys.path: %s'% sys.path) - return - if 'pagesopen' in dir(site): - try: - po = site.pagesopen() - return po - except: - print('"pagesopen" failed for site %s'% siteName) - return - else: - print('no function "pagesopen" in module: %s'% siteName) - return def findFolderWithIndex(self, root, allowed, ignore=None): """get the first folder with a file index.html""" @@ -1317,24 +1102,24 @@ def findFolderWithIndex(self, root, allowed, ignore=None): os.path.isfile(os.path.join(tryF, 'index.html')) or \ os.path.isfile(os.path.join(tryF, 'index.txt'))): return tryF - if ignore and type(ignore) == list: + if ignore and isinstance(ignore, (list, tuple)): # look in listdir and take first that is not to be ignored: try: List = os.listdir(root) except: - return + return None for d in List: if d in ignore: continue tryF = os.path.join(root, d) if os.path.isdir(tryF) and os.path.isfile(os.path.join(tryF, 'index.html')): return tryF + return None def gotResults_folder(self, words, fullResults): """collects the given command words and try to find the given folder """ - print('-------folder words: %s'% words) if len(words) == 1: ## catch folder with dgndictation, postpone here: self.gotFolder = True @@ -1353,61 +1138,54 @@ def gotResults_foldercommands(self, words, fullResults): different) """ if not self.wantedFolder: - print('rule foldercommands, no wantedFolder, return') + self.info('rule foldercommands, no wantedFolder, return') return - nextGit = nextRemote = False + nextRemote = False for w in words: if self.hasCommon(w, 'here'): - print("got Here: ", w) + self.info(f"got Here: {w}") self.Here = True elif self.hasCommon(w, 'new'): - print("got New: ", w) + self.info(f"got New: {w}") self.New = True elif self.hasCommon(w, 'paste'): - print("got Paste, set PastePath: ", w) + self.info(f"got Paste, set PastePath: {w}") self.PastePath = True elif self.hasCommon(w, 'on'): - print("got Remote: ", w) + self.info("got Remote: {w}") nextRemote = True elif nextRemote: remoteLetter = self.getFromInifile(w, 'letters', noWarning=1) remoteVirtualDrive = self.getFromInifile(w, 'virtualdrivesspoken', noWarning=1) if remoteLetter: - print('remoteLetter: %s'% remoteLetter) + self.info('remoteLetter: %s', remoteLetter) self.Remote = remoteLetter.upper() + ":" elif remoteVirtualDrive: self.Remote = self.virtualDriveDict[remoteVirtualDrive] - print('remoteVirtualDrive: %s, resolves to: %s'% (remoteVirtualDrive, self.Remote)) + self.info('remoteVirtualDrive: %s, resolves to: %s', remoteVirtualDrive, self.Remote) nextRemote = False - elif self.hasCommon(w, 'git'): - print("got Git: ", w) - nextGit = True - elif nextGit: - print("got gitCommand: ", w) - gitCommand = self.getFromInifile(w, 'gitfoldercommands') - self.Git = gitCommand - nextGit = False # again else: opt = self.getFromInifile(w, 'foldercommands') - print("got FolderOptions: ", opt) + self.info("got FolderOptions: %s", opt) self.FolderOptions.append(opt) def gotResults_namepathcopy(self, words, fullResults): """copy the name or the path of a folder, file or website """ if not self.catchRemember: - print("_folders, namepathcopy, do not know what to copy, folder, file or website") + self.info("_folders, namepathcopy, do not know what to copy, folder, file or website") return if self.hasCommon(words, "name"): what = "name" elif self.hasCommon(words, "path"): what = "path" else: - print("_folders, namepathcopy, choose copy name or path, not: %s"% repr(words)) + self.info("_folders, namepathcopy, choose copy name or path, not: %s", repr(words)) return + if self.catchRemember == "folder": if not self.wantedFolder: - print("_folders, namepathcopy, no valid folder") + self.info("_folders, namepathcopy, no valid folder") return self.wantedFolder = self.wantedFolder.rstrip("/\\") if what == "name": @@ -1416,7 +1194,7 @@ def gotResults_namepathcopy(self, words, fullResults): result = self.wantedFolder elif self.catchRemember == "file": if not self.wantedFile: - print("_folders, namepathcopy, no valid file") + self.info("_folders, namepathcopy, no valid file") return if what == "name": result = os.path.split(self.wantedFile)[-1] @@ -1425,20 +1203,22 @@ def gotResults_namepathcopy(self, words, fullResults): elif self.catchRemember == "website": if not self.wantedWebsite: - print("_folders, namepathcopy, no valid website") + self.info("_folders, namepathcopy, no valid website") return if what == 'name': result = self.wantedWebsite.split("/")[-1] else: result = self.wantedWebsite.split()[-1] - print('namepathcopy, result: %s (type: %s)'% (result, type(result))) - natqh.setClipboard(result, 13) # 13 unicode!! + else: + result = '' + self.info('namepathcopy, result: %s (type: %s)', result, type(result)) + unimacroutils.setClipboard(result, 13) # 13 unicode!! def gotResults_remember(self, words, fullResults): """treat the remember function, filling items in ini files """ if not self.catchRemember: - print('_folders, in remember rule, but nothing to remember') + self.info('_folders, in remember rule, but nothing to remember') return if self.catchRemember == "folder": self.rememberBase = self.getFolderBasenameRemember(self.wantedFolder) @@ -1469,24 +1249,22 @@ def gotResults_remember(self, words, fullResults): default = self.rememberBase section = 'files' else: - print('_folders, invalid value for catchRemember: %s'% self.catchRemember) + self.info('_folders, invalid value for catchRemember: %s', self.catchRemember) return prompt = "Remember in Unimacro _folders grammar" inifile = self.ini._file inifile = inifile.replace("\\", "/") text = '\n\n'.join(texts) - title = "bla bla bla" # not used if not self.checkForChanges: self.checkForChanges = 10 # switch this on 10 utterances pausetime = 3 # reset variables, no action in gotResults: self.wantedFile = self.wantedFolder = self.wantedWebsite = "" - print(f'thisDir: {thisDir}') - DNSIniDir = path('%DNSINIDIR%') - UnimacroDirectory = path('%UNIMACRODIRECTORY%') - print(f'UnimacroDirectory: {UnimacroDirectory}') - UnimacroGrammarsDirectory = path('%UNIMACROGRAMMARSDIRECTORY%') - print(f'UnimacroGrammarsDirectory: {UnimacroGrammarsDirectory}') + self.info(f'thisDir: {thisDir}') + UnimacroDirectory = envvars.expandEnvVariableAtStart('%Unimacro%') + self.info(f'UnimacroDirectory: {UnimacroDirectory}') + UnimacroGrammarsDirectory = envvars.expandEnvVariableAtStart('%UnimacroGrammars%') + self.info(f'UnimacroGrammarsDirectory: {UnimacroGrammarsDirectory}') makeFromTemplateAndExecute(UnimacroDirectory, "unimacrofoldersremembertemplate.py", UnimacroGrammarsDirectory, "rememberdialog.py", prompt, text, default, inifile, section, value, pausetime=pausetime) @@ -1501,13 +1279,13 @@ def get_active_explorer(self, hndle=None): for window in shell.Windows(): if int(window.HWND) == int(hndle): return window - print("_folders: no active explorer.") + self.info("_folders: no active explorer.") return None def get_current_directory(self, hndle=None): window = self.get_active_explorer(hndle) if window is None: - return + return None path = urllib.parse.unquote(window.LocationURL) for prefix in ["file:///", "http://", "https://"]: @@ -1519,8 +1297,8 @@ def get_current_directory(self, hndle=None): def get_selected_paths(self): window = self.get_active_explorer() if window is None: - print('get_selected_paths, cannot find application') - return + self.info('get_selected_paths, cannot find application') + return None items = window.Document.SelectedItems() paths = [] for item in collection_iter(items): @@ -1530,7 +1308,7 @@ def get_selected_paths(self): def get_selected_filenames(self): paths = self.get_selected_paths() if paths is None: - return + return None return [os.path.basename(p) for p in paths] def gotResults_thisfile(self, words, fullResults): @@ -1544,12 +1322,12 @@ def gotResults_thisfile(self, words, fullResults): ## wait for the mouse to have stoppede moving button, nClick = 'left', 1 if not self.doWaitForMouseToStop(): - print('_folders, thisfile, mouse did not stop, cannot click') + self.info('_folders, thisfile, mouse did not stop, cannot click') return - natqh.buttonClick(button, nClick) - natqh.visibleWait() + unimacroutils.buttonClick(button, nClick) + unimacroutils.visibleWait() - # print 'filenames: %s'% self.get_selected_filenames() + # self.info 'filenames: %s'% self.get_selected_filenames() self.wantedFile = None # paths = self.get_selected_paths() # if paths: @@ -1558,46 +1336,46 @@ def gotResults_thisfile(self, words, fullResults): # self.wantedFile = p # break # else: - # print "warning, thisfile: no valid file found" + # self.info "warning, thisfile: no valid file found" # # else: - natqh.saveClipboard() - natqh.Wait() + unimacroutils.saveClipboard() + unimacroutils.Wait() keystroke("{ctrl+c}") - natqh.Wait() + unimacroutils.Wait() paths1 = natlinkclipboard.Clipboard.get_system_folderinfo() - natqh.restoreClipboard() + unimacroutils.restoreClipboard() if paths1: paths1 = [p for p in paths1 if os.path.isfile(p)] paths2 = get_selected_files(folders=False) - print('get_system_folderinfo: %s'% paths1) - print('get_selected_files: %s'% paths2) + self.info('get_system_folderinfo: %s', paths1) + self.info('get_selected_files: %s', paths2) if paths1 and paths2: if paths1 == paths2: paths = paths1 else: - print('_thisfile, different info for both methods:\nVia Clipboard %s\nVia this module functions: %s'% \ - (repr(paths1), repr(paths2))) + self.info('_thisfile, different info for both methods:\nVia Clipboard %s\nVia this module functions: %s', \ + repr(paths1), repr(paths2)) paths = paths2 elif paths1: - print('_thisfile, only paths1 (via clipboard) has data: %s'% repr(paths1)) + self.info('_thisfile, only paths1 (via clipboard) has data: %s', repr(paths1)) paths = paths1 elif paths2: paths = paths2 - print('_thisfile, only paths2 (this module functions) has data: %s'% repr(paths2)) + self.info('_thisfile, only paths2 (this module functions) has data: %s', repr(paths2)) else: - print('no paths info found with either methods') + self.info('no paths info found with either methods') paths = None if not paths: - print("no selected file found") + self.info("no selected file found") return self.wantedFile = paths[0] if len(paths) > 1: - print("warning, more files selected, take the first one: %s"% self.wantedFile) - print('wantedFile: %s'% self.wantedFile) + self.warning("warning, more files selected, take the first one: %s", self.wantedFile) + self.info('wantedFile: %s', self.wantedFile) self.catchRemember = "file" def gotResults_disc(self,words,fullResults): @@ -1606,7 +1384,7 @@ def gotResults_disc(self,words,fullResults): if letter: f = letter + ":\\" else: - print('_folders, ruls disc, no letter provided: %s'% words) + self.info('_folders, ruls disc, no letter provided: %s', words) return if self.nextRule in ['foldercommands']: @@ -1625,30 +1403,30 @@ def gotResults_file(self,words,fullResults): File = self.subfilesDict[wantedFile] extension =self.getFromInifile(words, 'extensions', noWarning=1) if extension: - File, old_extension =os.path.splitext (File) + File, _old_extension = os.path.splitext (File) File = File +'.' + extension - print('got file: %s'% File) + self.info('got file: %s', File) File = os.path.join(self.activeFolder, File) if not os.path.isfile(File): - print('folders, file, from subfilesList, not a valid path: %s (return None)'% File) + self.info('folders, file, from subfilesList, not a valid path: %s (return None)', File) File = None else: - print('file from subfileslist: %s'% File) + self.info('file from subfileslist: %s', File) self.catchRemember = "file" if not File: try: File = self.filesDict[wantedFile] except KeyError: - print('file cannot be found in filesDict: %s (and not in subfilesDict either)'% wantedFile) + self.info('file cannot be found in filesDict: %s (and not in subfilesDict either)', wantedFile) return File = self.substituteFolder(File) - print("_folders, get file: actual filename (fixed fileslist): %s"% File) + self.info("_folders, get file: actual filename (fixed fileslist): %s", File) extension =self.getFromInifile(words, 'extensions', noWarning=1) if extension: - File, old_extension =os.path.splitext (File) + File, _old_extension =os.path.splitext (File) File = File +'.' + extension if not os.path.isfile(File): - print('invalid file: %s'% File) + self.info('invalid file: %s', File) return if self.nextRule in ["filecommands", "remember"]: self.wantedFile = File @@ -1659,10 +1437,9 @@ def gotResults_file(self,words,fullResults): def gotResults_filecommands(self, words, fullResults): if not self.wantedFile: - print('rule filecommands, no wantedFile, return') + self.info('rule filecommands, no wantedFile, return') return # print 'filecommands: %s'% words - kw = {} OpenWith = Remote = False for w in words: if self.hasCommon(w, 'open with'): @@ -1676,23 +1453,15 @@ def gotResults_filecommands(self, words, fullResults): remoteLetter = self.getFromInifile(w, 'letters', noWarning=1) remoteVirtualDrive = self.getFromInifile(w, 'virtualdrivesspoken', noWarning=1) if remoteLetter: - print('remoteLetter: %s'% remoteLetter) + self.info('remoteLetter: %s', remoteLetter) self.Remote = remoteLetter.upper() + ":" elif remoteVirtualDrive: self.Remote = self.virtualDriveDict[remoteVirtualDrive] - print('remoteVirtualDrive: %s, resolves to: %s'% (remoteVirtualDrive, self.Remote)) + self.info('remoteVirtualDrive: %s, resolves to: %s', remoteVirtualDrive, self.Remote) Remote = False - elif self.hasCommon(w, 'git'): - print("got Git: ", w) - Git = True - elif Git: - print("got gitCommand: ", w) - gitCommand = self.getFromInifile(w, 'gitfilecommands') - self.Git = gitCommand - Git = False # again else: act = self.getFromInifile(w, 'foldercommands') - print("got FileCommand: ", act) + self.info("got FileCommand: ", act) self.FileOptions.append(act) def gotResults_thisfolder(self,words,fullResults): @@ -1702,89 +1471,85 @@ def gotResults_thisfolder(self,words,fullResults): assume foldercommands or remember action follows, so only rememberBase and wantedFolder are given """ - cb = natlinkclipboard.Clipboard(save_clear=True) + # cb = natlinkclipboard.Clipboard(save_clear=True) ##TODO if self.hasCommon(words[0], "here"): ## wait for the mouse to have stoppede moving button, nClick = 'left', 1 if not self.doWaitForMouseToStop(): - print("_folders, command thisfolder: doWaitForMouseToStop fails") + self.info("_folders, command thisfolder: doWaitForMouseToStop fails") return - natqh.buttonClick(button, nClick) - natqh.visibleWait() + unimacroutils.buttonClick(button, nClick) + unimacroutils.visibleWait() # now got attention, go ahead: self.wantedFolder = None - natqh.saveClipboard() - natqh.Wait() + unimacroutils.saveClipboard() + unimacroutils.Wait() keystroke("{ctrl+c}") - natqh.Wait() + unimacroutils.Wait() paths1 = natlinkclipboard.Clipboard.Get_folderinfo() + unimacroutils.restoreClipboard() if paths1: paths1 = [p for p in paths1 if os.path.isdir(p)] paths2 = get_selected_files(folders=True) - natqh.Wait() + unimacroutils.Wait() if paths1 and paths2: if paths1 == paths2: paths = paths1 else: - print('_thisfolder, different info for both methods:\nVia Clipboard %s\nVia this module functions: %s'% \ - (repr(paths1), repr(paths2))) + self.info('_thisfolder, different info for both methods:\nVia Clipboard %s\nVia this module functions: %s', \ + repr(paths1), repr(paths2)) paths = paths2 elif paths1: - print('_thisfolder, only paths1 (via clipboard) has data: %s'% repr(paths1)) + self.info('_thisfolder, only paths1 (via clipboard) has data: %s', repr(paths1)) paths = paths1 elif paths2: # paths = paths2 - print('_thisfolder, only paths2 (this module functions) has data: %s'% repr(paths2)) + self.info('_thisfolder, only paths2 (this module functions) has data: %s', repr(paths2)) else: - print('no paths info found with either methods') + self.info('no paths info found with either methods') paths = None - print('paths:::: %s'% paths) # + self.info('paths:::: %s', paths) # if paths: self.wantedFolder = paths[0] if len(paths) > 1: - print("warning, more items selected, take the first one: %s"% self.wantedFolder) + self.info("warning, more items selected, take the first one: %s", self.wantedFolder) elif self.activeFolder: - print('take activeFolder: %s'% self.activeFolder) + self.info('take activeFolder: %s', self.activeFolder) self.wantedFolder = self.activeFolder else: - print('"this folder" no selected folder found') + self.info('"this folder" no selected folder found') return if os.path.isdir(self.wantedFolder): - # print '_folders, this folder, wantedFolder: %s'% self.wantedFolder + # self.info '_folders, this folder, wantedFolder: %s'% self.wantedFolder self.catchRemember = "folder" # in case remember follows else: - print('_folders, wantedFolder not a valid folder: %s'% self.wantedFolder) + self.info('_folders, wantedFolder not a valid folder: %s', self.wantedFolder) # def gotResults_folderup(self,words,fullResults): """ go up in hierarchy""" upn = self.getNumberFromSpoken(words[-1]) #print 'folderup: %s'% upn - m = natlink.getCurrentModule() - prog, title, topchild, classname, hndle = natqh.getProgInfo(modInfo=m) - hndle = m[2] - Iam2x = prog == '2xexplorer' + _progpath, prog, title, _topchild, classname, hndle = self.progInfo IamExplorer = prog == 'explorer' - IamChild32770 = topchild, hndle == 'child' and win32gui.GetClassName(hndle) == '#32770' - if IamChild32770: - self.className = '#32770' + IamChild32770 = classname == '#32770' browser = prog in ['iexplore', 'firefox','opera', 'netscp'] # print 'iambrowser: %s Iamexplorer: %s'% (browser, IamExplorer) - istop = self.getTopOrChild( m, childClass="#32770" ) # True if top window + istop = self.getTopOrChild(self.progInfo, childClass="#32770") # True if top window if IamChild32770: - print("IamChild32770: ", self.activeFolder) + self.info(f"IamChild32770: {self.activeFolder}") if not self.activeFolder: - self.activeFolder = mess.getFolderFromDialog(hndle, self.className) - print("IamChild32770 getFolderFromDialog: ", self.activeFolder) + self.activeFolder = mess.getFolderFromDialog(hndle, classname) + self.info(f"IamChild32770 getFolderFromDialog: {self.activeFolder}") if self.activeFolder: newfolder = self.goUpInPath(self.activeFolder, upn) - #print 'newfolder (up %s): %s'% (upn, newfolder) - self.gotoInThisDialog(newfolder, hndle, self.className) + #self.info 'newfolder (up %s): %s'% (upn, newfolder) + self.gotoInThisDialog(newfolder, hndle, classname) else: - print('method not working (any more) for #32770: %s'% title) + self.info('method not working (any more) for #32770: %s', title) elif not istop: # child window actions @@ -1792,36 +1557,36 @@ def gotResults_folderup(self,words,fullResults): action("<>; {shift+tab}") action("{backspace %s}"% upn) elif browser: - natqh.saveClipboard() + unimacroutils.saveClipboard() keystroke('{alt+d}{extend}{shift+exthome}{ctrl+c}') - t = natqh.getClipboard() + t = unimacroutils.getClipboard() prefix, path = t.split('://') T = path.split('/') if len(T) > upn: - T = T[:-upn] + T = T[:-int(upn)] else: T = T[0] keystroke(prefix + '://' + '/'.join(T)) keystroke('{enter}') - natqh.restoreClipboard() + unimacroutils.restoreClipboard() elif IamExplorer: if not self.activeFolder: self.activeFolder = mess.getFolderFromCabinetWClass(hndle) if self.activeFolder: newfolder = self.goUpInPath(self.activeFolder, upn) - print('newfolder (up %s): %s'% (upn, newfolder)) + self.info('newfolder (up %s): %s', upn, newfolder) self.gotoInThisComputer(newfolder) else: - print('method not working any more, going folder up') + self.info('method not working any more, going folder up') action("MP 1, 50, 10, 0") - for i in range(upn): + for _i in range(upn): action("{backspace} VW") else: - print('yet to implement, folder up for %s'% prog) + self.info('yet to implement, folder up for %s', prog) - #print 'had folder up: %s'% words + #self.info 'had folder up: %s'% words def substituteFolder(self, folder): @@ -1835,9 +1600,9 @@ def substituteFolder(self, folder): """ folder = folder.replace('/', '\\') folder = self.substituteEnvVariable(folder) - if not self.virtualDriveDict: - #print 'no virtualDriveDict, return %s'% folder - return folder + # if not self.virtualDriveDict: + # #print 'no virtualDriveDict, return %s'% folder + # return folder if folder in self.virtualDriveDict: drive, rest = folder, "" elif folder.find(':\\') > 0: @@ -1854,10 +1619,8 @@ def substituteFolder(self, folder): vd = self.substituteFolder(vd) if rest: return os.path.normpath(os.path.join(vd, rest)) - else: - return os.path.normpath(vd) - else: - return os.path.normpath(folder) + return os.path.normpath(vd) + return os.path.normpath(folder) def substituteEnvVariable(self,folder): """honor environment variables like %HOME%, %PROGRAMFILES% @@ -1867,7 +1630,7 @@ def substituteEnvVariable(self,folder): With expandEnvVars, also NATLINK and related variables can be handled. NATLINKDIRECTORY, COREDIRECTORY etc. """ - substitute = natlinkcorefunctions.expandEnvVariables(folder) + substitute = envvars.expandEnvVariables(folder) return substitute def substituteFilename(self, filename): @@ -1945,88 +1708,61 @@ def acceptExtension(self, ext): """ if ext.lower() in self.acceptFileExtensions: return 1 - + return None + def acceptFileName(self, item, extensions=None): """return 1 if filename ok, only filename expected here """ for pat in self.ignoreFilePatterns: if fnmatch.fnmatch(item, pat): - return + return None return 1 def gotoWebsite(self, f): """goto the file f, options in instance variables FileOptions: list - Git (with gitfileoptions), False or the git action to be taken Remote, False or the virtual drive to be inserted Open, False or app to Open with (default) Edit, False or app to Edit with, if fails, take Notepad - ##special case for citrix """ if self.Open: - print("gotoWebsite %s with: %s", (f, self.Open)) + self.info("gotoWebsite %s with: %s", f, self.Open) else: - print("gotoWebsite: ", f) + self.info("gotoWebsite: %s", f) self.openWebsiteDefault(f, openWith=self.Open) def gotoFile(self, f): """goto the file f, options in instance variables FileOptions: list - Git (with gitfileoptions), False or the git action to be taken Remote, False or the virtual drive to be inserted Open, False or app to Open with (default) Edit, False or app to Edit with, if fails, take Notepad - - ##special case for citrix """ - if self.citrixApps: - prog = natqh.getProgInfo()[0] - - print('citrixApps: %s app: %s'% (self.citrixApps, prog)) - if prog in self.citrixApps: - print('doing action gotoFolder for citrixApp: %s'% prog) - action("<>") - keystroke(f) - - # keystroke("{enter}") - return - if not os.path.isfile(f): self.DisplayMessage('file does not exist: %s'% f) return - m = natlink.getCurrentModule() - prog, title, topchild, classname, hndle = natqh.getProgInfo(modInfo=m) - # istop logic, with functions from action.py module, settings from: # child behaves like top = natspeak: dragon-balk # top behaves like child = komodo: find, komodo; thunderbird: bericht opslaan # in actions.ini: - - istop = self.getTopOrChild( m, childClass="#32770") # True if top + istop = self.getTopOrChild( self.progInfo, childClass="#32770") # True if top if self.Remote: - print('Remote: %s'% self.Remote) + self.info('Remote: %s', self.Remote) f = self.getValidFile(f, self.Remote) if not f: return - if self.Git: - print('git command "%s" for file "%s"'% (self.Git, f)) - self.doGitCommand(self.Git, f) - return - - mode = None - if self.Edit: - mode = 'edit' + mode = 'edit' if self.Open: mode = 'open' if self.CopyNamePath: - natqh.setClipboard(f) + unimacroutils.setClipboard(f) return if self.Paste: action("SCLIP %s"%f) @@ -2035,19 +1771,19 @@ def gotoFile(self, f): if not istop: # child window actions # put the mouse in the left top corner of the window: - print("Open file from child window: %s"% f) + self.info("Open file from child window: %s", f) action("RMP 1, 0.02, 0.05, 0") action('<>') - natqh.saveClipboard() + unimacroutils.saveClipboard() keystroke('{Ctrl+x}') keystroke(f) action('<>') keystroke('{Ctrl+v}') - natqh.restoreClipboard() + unimacroutils.restoreClipboard() keystroke('{Shift+Tab}') else: # top or top behaviourthis - self.openFileDefault(f) + self.openFileDefault(f, mode=mode) def openFileDefault(self, filename, mode=None, windowStyle=None, name=None, openWith=None): """open the file according to the options given @@ -2058,10 +1794,10 @@ def openFileDefault(self, filename, mode=None, windowStyle=None, name=None, open """ ## action('CW') if not os.path.isfile(filename): - print('file does not exist, cannot open: %s'% filename) + self.info('file does not exist, cannot open: %s', filename) return if not ancestor.openFileDefault(self, filename, mode=mode, openWith=openWith): - print('could not open %s (mode: %s, openWith: %s)'% (filename, mode, openWith)) + self.info('could not open %s (mode: %s, openWith: %s)', filename, mode, openWith) return try: # try is needed in case function is called from another class (dirty trick with _control, sorry) @@ -2071,7 +1807,7 @@ def openFileDefault(self, filename, mode=None, windowStyle=None, name=None, open except AttributeError: pass - def openFolderDefault(self, foldername, mode=None, openWith=None): + def openFolderDefault(self, foldername, mode=None, windowStyle=None, openWith=None): """open the folder in the default window LW() if succeed, perform optional additional options. @@ -2081,12 +1817,12 @@ def openFolderDefault(self, foldername, mode=None, openWith=None): #print 'going to open folder: %s'% foldername if not ancestor.openFolderDefault(self, foldername, mode=mode, openWith=openWith): - print('failed to open folder: %s'% foldername) + self.info('failed to open folder: %s', foldername) return for act in self.FolderOptions: if act: - print("openFolderDefault, action: %s"% act) + self.info("openFolderDefault, action: %s", act) action(act) # This is the function which does the real work, depending on the @@ -2094,7 +1830,7 @@ def openFolderDefault(self, foldername, mode=None, openWith=None): def gotoFolder(self, f): """go to the specified folder - all the options are via instance variables, New, Here, Copy, Paste, Remote, Git (all False by default) + all the options are via instance variables, New, Here, Copy, Paste, Remote (all False by default) and FolderOptions (a list, initially empty). f = the (local) folder to go to @@ -2107,7 +1843,6 @@ def gotoFolder(self, f): --Remote: pass the (virtual) drive where the folder is wanted --Copy: investigate --Paste: only paste the path at the place where you are. - --Git: do a git command on the folder. To be done. this is the central routine, with complicated strategy for getting it, in pseudocode: @@ -2151,69 +1886,60 @@ def gotoFolder(self, f): else: if part of path is common, switch to that and goto folder - ## remove subversion support, - ## git support if git executable isdefined in section [general] - - ##special if citrixApps is set, just open the folder. - """ ## undoncitionally if folderoption New is used: if self.New: self.openFolderDefault(f) return - prog = natqh.getProgInfo()[0] - if self.citrixApps: - - print('citrixApps: %s app: %s'% (self.citrixApps, prog)) - if prog in self.citrixApps: - print('doing action gotoFolder for citrixApp: %s'% prog) - action("<>") - keystroke(f) - keystroke("{enter}") - return + prog = self.progInfo.prog f = os.path.normpath(f) if not os.path.isdir(f): self.DisplayMessage('folder does not exist: %s'% f) return if prog == 'cmd': - print("_folder, for cmd: %s"% f) + self.info("_folder, for cmd: %s", f) # t = " " + f action('SCLIP(%s)'% f) return - if self.Git: - self.doGitCommand(self.Git, f) - - # xx = self.xxExplorer if self.Remote: - print('Remote: %s'% self.Remote) + self.info('Remote: %s', self.Remote) f = self.getValidDirectory(f, self.Remote) - print('Remote: %s'% f) + self.info('Remote: %s', f) if not f: return if self.PastePath: action("SCLIP(%s)"%f) - print("PastePath: %s"% f) + self.info("PastePath: %s", f) return # if self.CopyNamePath: - print('put path on clipboard: "%s"'% f) - natqh.setClipboard(f) + self.info('put path on clipboard: "%s"', f) + unimacroutils.setClipboard(f) return - m = natlink.getCurrentModule() - istop = self.getTopOrChild( m, childClass="#32770" ) - prog, title, topchild, classname, hndle = natqh.getProgInfo(modInfo=m) + istop = self.getTopOrChild(self.progInfo, childClass="#32770") + prog = self.progInfo.prog + hndle = self.progInfo.hndle if not hndle: - print('_folders, gotoFolder: no window handle found, return') + self.info('_folders, gotoFolder: no window handle found, return') # Iam2x = prog == '2xexplorer' IamExplorer = prog == 'explorer' - browser = prog in ['iexplore', 'firefox','opera', 'netscp'] + _browser = prog in ['iexplore', 'firefox','opera', 'netscp', 'brave'] ## print 'iambrowser:', browser ## print 'xx: %s, Iam2x: %s, IamExplorer: %s'% (xx, Iam2x, IamExplorer) ## IamExplorer = prog == 'explorer' + try: + classname = win32gui.GetClassName(hndle) + except: + logger.debug('Invalid hndle for GetClassName: {hndle}') + classname = '' + IamChild32770 = (not istop) and classname == '#32770' + + + IamChild32770 = (not istop) and win32gui.GetClassName(hndle) == '#32770' if IamChild32770: self.className = '#32770' @@ -2223,22 +1949,21 @@ def gotoFolder(self, f): # print("go from here activeFolder: %s"% self.activeFolder) self.gotoInThisDialog(f, hndle, self.className) return - else: - print("no files/folder dialog, treat as top window") - self.openFolderDefault(f) - return + self.info("no files/folder dialog, treat as top window") + self.openFolderDefault(f) + return if not istop: # child window actions # put the mouse in the left top corner of the window: - print("_folders, child window, comes ever here???") + self.info("_folders, child window, comes ever here???") action("RMP 1, 0.02, 0.05, 0") action('<>') - natqh.saveClipboard() + unimacroutils.saveClipboard() keystroke('{Ctrl+x}') keystroke(f) action('<>') keystroke('{Ctrl+v}') - natqh.restoreClipboard() + unimacroutils.restoreClipboard() keystroke('{Shift+Tab}') return @@ -2284,37 +2009,39 @@ def gotoFolder(self, f): if exactList: ## print 'exactList %s' % (exactList) if len(exactList) > 1: - print('warning, 2 matching windows: %s'% exactList) + self.info('warning, 2 matching windows: %s', exactList) t, h = exactList[0] - natqh.SetForegroundWindow(h) + unimacroutils.SetForegroundWindow(h) elif overList: -## print 'over List %s' % (overList) +## self.info 'over List %s' % (overList) # eg f = d:\\a\\b # and elements of overList are d:\\a\\b\\c and d:\\a\\b\\c\\d # goto shortest element # later make choice list of where to go if len(overList) == 1: t, h = overList[0] - natqh.SetForegroundWindow(h) + unimacroutils.SetForegroundWindow(h) lenMin = 999 for t, h in overList: ## print 'nearList: %s'% nearList if len(t) < lenMin: take = h lenMin = len(t) - + break + else: ## TODO QH simplify this! + take = 0 ## print 'i: %s, take: %s'% (i, nearList[i]) toHandle = take - + thisHandle = hndle ## ?? TODO if thisHandle == toHandle: self.gotoInThisComputer(f) else: - natqh.SetForegroundWindow(take) + unimacroutils.SetForegroundWindow(take) elif underList: # eg f = d:\\a\\b\\c # elementes of underList are d:\\a d:\\a\\b etc. # go to longest element and switch in that window to folder - print('under list, go to first folder') + self.info('under list, go to first folder') lenMax = 0 for t, h in underList: @@ -2322,7 +2049,7 @@ def gotoFolder(self, f): if len(t) > lenMax: take = h lenMax = len(t) - if natqh.SetForegroundWindow(take): + if unimacroutils.SetForegroundWindow(take): self.gotoInThisComputer(f) elif restList: @@ -2333,10 +2060,10 @@ def gotoFolder(self, f): ## print 'take: ', `take` if take: t, h = take - if natqh.SetForegroundWindow(h): + if unimacroutils.SetForegroundWindow(h): self.gotoInThisComputer(f) else: - print('could not set foregroundwindow: %s'% h) + self.info('could not set foregroundwindow: %s', h) self.openFolderDefault(f) else: @@ -2344,11 +2071,11 @@ def gotoFolder(self, f): self.openFolderDefault(f) else: # no this computer windows (yet) - print("grammar folders shouldn't be here!") + self.info("grammar folders shouldn't be here!") def getValidDirectory(self, f, remote): - """substitute remote in front of f and try to find a valid directory + r"""substitute remote in front of f and try to find a valid directory (tried in pathmanipulate_folders_grammar.py, private Quintijn) f = r'C:\Documenten\Quintijn' @@ -2366,8 +2093,7 @@ def getValidDirectory(self, f, remote): (if E: is a valid backup drive) """ - fdrive, fdir = os.path.splitdrive(f) - remdrive, rempart = os.path.splitdrive(remote) + _fdrive, fdir = os.path.splitdrive(f) fparts = [part for part in fdir.split(os.sep) if part] while fparts: fpart = os.sep.join(fparts) @@ -2375,11 +2101,11 @@ def getValidDirectory(self, f, remote): if os.path.isdir(tryF): return tryF fparts.pop(0) - print('_folders, no valid remote folder found for %s and remote: %s'% (f, remote)) + self.info('_folders, no valid remote folder found for %s and remote: %s', f, remote) + return '' def getValidFile(self, f, remote): - fdrive, fdir = os.path.splitdrive(f) - remdrive, rempart = os.path.splitdrive(remote) + _fdrive, fdir = os.path.splitdrive(f) fparts = [part for part in fdir.split(os.sep) if part] while fparts: fpart = os.sep.join(fparts) @@ -2387,41 +2113,9 @@ def getValidFile(self, f, remote): if os.path.isfile(tryF): return tryF fparts.pop(0) - print('_folders, no valid remote file found for %s and remote: %s'% (f, remote)) + self.info('_folders, no valid remote file found for %s and remote: %s', f, remote) + return '' - - def getListOfSites(self, root): - """return list of sitenames, to be found as python files in root - - """ - pyfiles = [f for f in os.listdir(root) if f.endswith('.py')] - #print 'pyfiles for sites: %s'% pyfiles - D = {} - entries = self.ini.get('sites') - for p in pyfiles: - trunk = p[:-3] - if not reOnlyLowerCase.match(trunk): - continue # only lowercase items can be a sites item, so __init__ and HTMLgen etc are skipped - if trunk in entries: - spokenList = self.ini.getList('sites', trunk) - if not spokenList: - #print 'empty item in siteslist: %s'% trunk - continue - else: - for spoken in spokenList: - spoken = self.spokenforms.correctLettersForDragonVersion(spoken) - D[spoken] = trunk - else: - # make new entry in sites section - if len(trunk) <= 3: - spoken = '. '.join(list(trunk.upper()))+'.' - else: - spoken = trunk - spoken = self.spokenforms.correctLettersForDragonVersion(spoken) - D[spoken] = trunk - #print 'set in sites: %s -> %s'% (trunk, spoken) - self.ini.set('sites', trunk, spoken) - return D def gotResults(self, words,fullResults): """at last do most of the actions, depending on the variables collected in the rules. @@ -2432,30 +2126,6 @@ def gotResults(self, words,fullResults): self.gotoFile(self.wantedFile) if self.wantedWebsite: self.gotoWebsite(self.wantedWebsite) - - - def doGitCommand(self, command, path): - """launch git with command and path - """ - args = '/command:%s /path:""%s""'% (command, path) - - # Construct arguments and spawn TortoiseSVN. - name = "git %s %s"% (command, path) - print('future git %s, %s'% (name, args)) - ## does not work (yet)... - # natqh.AppBringUp(name, self.doGit, args) - -# return 1 - - def doStart2xExplorer(self): - """starting the 2xExplorer, obsolete - - """ - command = 'AppBringUp "%s"'% self.xxExplorer -## print 'starting 2xExplorer: %s'% command - natlink.execScript(command) - natqh.Wait(1.0) - keystroke("{alt+space}{extdown 4}{enter}") def gotoInThisComputer(self, f): """perform the keystrokes to go to a folder in this computer @@ -2478,18 +2148,18 @@ def gotoInThisDialog(self, f, hndle, className): elif os.path.isfile(f): folder, filename = os.path.split(f) else: - print('invalid target for gotoInThisDialog: %s'% f) + self.info('invalid target for gotoInThisDialog: %s', f) return if folder != activeFolder: # action("SCLIP %s{enter}") # here SCLIP does not work... keystroke(f) keystroke('{enter}') - for i in range(4): + for _i in range(4): action('W') keystroke('{shift+tab}') if filename: - action("SCLIP %s"% filename) + action("SCLIP %s", filename) # keystroke(filename) def gotoInOtherExplorer(self, f): @@ -2501,16 +2171,16 @@ def gotoInOtherExplorer(self, f): if self.useOtherExplorer == "xplorer2": keystroke("{shift+tab}%s{enter}{down}{up}"% f) else: - print('_folders, please specify in function "gotoInOtherExplorer" for "use other explorer": "%s"'% self.useOtherExplorer) + self.info('_folders, please specify in function "gotoInOtherExplorer" for "use other explorer": "%s"', self.useOtherExplorer) - def goUpInPath(self, Path, nsteps=None): + def goUpInPath(self, PATH, nsteps=None): """return a new path, n steps up in hierarchy, default 1 """ if not nsteps: nsteps = 1 - for i in range(nsteps): - Path = os.path.normpath(os.path.join(Path, '..')) - return Path + for _i in range(nsteps): + PATH = os.path.normpath(os.path.join(PATH, '..')) + return PATH def gotoIn2xExplorer(self, f): """perform the keystrokes to go to a folder in the 2xExplorer, obsolete @@ -2522,17 +2192,17 @@ def gotoIn2xExplorer(self, f): def doStartWindowsExplorer(self): - natqh.rememberWindow() + unimacroutils.rememberWindow() startExplorer = self.ini.get('general', 'start windows explorer') action(startExplorer) try: - natqh.waitForNewWindow(50, 0.05) # 2,5 seconds max - except natqh.NatlinkCommandTimeOut: - print('Error with action "start windows explorer" (%s) from command in grammar + "_folders".' % \ + unimacroutils.waitForNewWindow(50, 0.05) # 2,5 seconds max + except unimacroutils.NatlinkCommandTimeOut: + self.info('Error with action "start windows explorer" (%s) from command in grammar + "_folders".' , \ startExplorer) - print('Correct in ini file by using the command: ' + {'enx': "Edit Folders", + self.info('Correct in ini file by using the command: ' + {'enx': "Edit Folders", 'nld': "Bewerk folders"}[self.language]) - return + return None return 1 @@ -2540,7 +2210,6 @@ def fillDefaultInifile(self, ini=None): """initialize as a starting example the ini file (obsolete) """ - pass def getLongestCommon(tupleList, f): @@ -2558,6 +2227,7 @@ def getLongestCommon(tupleList, f): m = nCommon if hToTake: return pToTake, hToTake + return None def getCommonLength(a, b): i = 0 @@ -2576,14 +2246,14 @@ def getExplorerTitles(): """ TitlesHandles = [] ## Classes come from global variable at top of this module - ##print 'Classes:', Classes + ##self.info 'Classes:', Classes ## Classes = None win32gui.EnumWindows(getExplWindowsWithText, (TitlesHandles, Classes)) return TitlesHandles def getExplWindowsWithText(hwnd, th): - TH, Classes = th - if win32gui.GetClassName(hwnd) in Classes: + TH, classes = th + if win32gui.GetClassName(hwnd) in classes: # wTitle = win32gui.GetWindowText(hwnd).strip() # ansi wTitle = getwindowtext(hwnd).strip() if wTitle and hwnd: @@ -2619,7 +2289,7 @@ def cross_loop_alternatives(*sequences): yield () def loop_through_alternative_paths(pathdefinition): - """can hold alternatives (a|b) + r"""can hold alternatives (a|b) so "(C|D):/natlink" returns first "C:/natlink" and then "D:/natlink". with more alternatives more items are returned "(C:|D:|E:)\Document(s|en)" @@ -2644,7 +2314,7 @@ def get_clipboard_formats(): while f: formats.append(f) f = win32clipboard.EnumClipboardFormats(f) - # print '_folders, clipboard formats: %s'% formats + # self.info '_folders, clipboard formats: %s'% formats return formats def get_selected_files(folders=False): @@ -2658,7 +2328,7 @@ def get_selected_files(folders=False): time.sleep(0.1) files = get_clipboard_files(folders) # cb.copy_to_system() - # print 'files: %s'% files + # self.info 'files: %s'% files return files def get_clipboard_files(folders=False): @@ -2666,27 +2336,30 @@ def get_clipboard_files(folders=False): Enumerate clipboard content and return files either directly copied or highlighted path copied ''' - files = None - win32clipboard.OpenClipboard() - f = get_clipboard_formats() - if win32clipboard.CF_HDROP in f: - files = win32clipboard.GetClipboardData(win32clipboard.CF_HDROP) - else: - # print 'get_clipboard_files, not expected clipboard format CF_HDROP, but %s'% f - if win32clipboard.CF_UNICODETEXT in f: - files = [win32clipboard.GetClipboardData(win32clipboard.CF_UNICODETEXT)] - elif win32clipboard.CF_TEXT in f: - files = [win32clipboard.GetClipboardData(win32clipboard.CF_TEXT)] - elif win32clipboard.CF_OEMTEXT in f: - files = [win32clipboard.GetClipboardData(win32clipboard.CF_OEMTEXT)] - if not files: - # print "get_clipboard_files, no files found from clipboard" - return - if folders: - files = [f for f in files if os.path.isdir(f)] if files else None - else: - files = [f for f in files if os.path.isfile(f)] if files else None - win32clipboard.CloseClipboard() + try: + win32clipboard.OpenClipboard() + f = get_clipboard_formats() + if win32clipboard.CF_HDROP in f: + files = win32clipboard.GetClipboardData(win32clipboard.CF_HDROP) + else: + # self.info 'get_clipboard_files, not expected clipboard format CF_HDROP, but %s'% f + if win32clipboard.CF_UNICODETEXT in f: + files = [win32clipboard.GetClipboardData(win32clipboard.CF_UNICODETEXT)] + elif win32clipboard.CF_TEXT in f: + files = [win32clipboard.GetClipboardData(win32clipboard.CF_TEXT)] + elif win32clipboard.CF_OEMTEXT in f: + files = [win32clipboard.GetClipboardData(win32clipboard.CF_OEMTEXT)] + else: + files = [] ## OK? Quintijn + if not files: + # self.info "get_clipboard_files, no files found from clipboard" + return None + if folders: + files = [f for f in files if os.path.isdir(f)] if files else None + else: + files = [f for f in files if os.path.isfile(f)] if files else None + finally: + win32clipboard.CloseClipboard() return files def makeFromTemplateAndExecute(unimacrofolder, templatefile, unimacrogrammarsfolder, exefile, prompt, text, default, inifile, section, value, pausetime=0): @@ -2694,7 +2367,9 @@ def makeFromTemplateAndExecute(unimacrofolder, templatefile, unimacrogrammarsfol meant for setting up a inputbox dialog """ - encoding, bom, Text = readwritefile.readAnything(os.path.join(unimacrofolder, templatefile)) + rwfile = readwritefile.ReadWriteFile() + logger.info('unimacrofolder: %s, unimacrofolder') + Text = rwfile.readAnything(os.path.join(unimacrofolder, templatefile)) # print(f'OldText: {Text}') for orig, toreplace in [('$prompt$', prompt), ('$default$', default), ('$text$', text), ('$inifile$', inifile) , ('$value$', value), ('$section$', section), @@ -2705,41 +2380,36 @@ def makeFromTemplateAndExecute(unimacrofolder, templatefile, unimacrogrammarsfol raise ValueError(f'makeFromTemplateAndExecute, outputfile should end with ".py", not {exefile}') if pausetime: outputfile = exefile - pythonexe = path(sys.prefix)/'python.exe' + pythonexe = Path(sys.prefix)/'python.exe' else: outputfile = exefile + 'w' - pythonexe = path(sys.prefix)/'pythonw.exe' + pythonexe = Path(sys.prefix)/'pythonw.exe' outputpath = os.path.join(unimacrogrammarsfolder, outputfile) - readwritefile.writeAnything(outputpath, encoding, bom, Text) + rwfile.writeAnything(outputpath, Text) # print('wrote to: %s'% outputfile) # print(f'output dialog: {outputpath}, python: {pythonexe}') - UnimacroBringUp(pythonexe.normpath(), outputpath) + UnimacroBringUp(str(pythonexe), outputpath) - -def changeCallback(type, args): - """special behaviour for martijn""" - if ((type == 'mic') and (args=='on')): - user = natqh.getUser() ## different functions#########################################3 outlookApp = None outlookAppProgram = None def connectOutlook(): """connect to outlook""" + #pylint:disable=W0603 global outlookApp, outlookAppProgram if outlookAppProgram != 'outlook' or not outlookApp: pass #outlookApp = win32com.client.Dispatch('Outlook.Application') if outlookApp: - print('outlook application collected') - return outlookApp - else: - print('outlook not connected') - outlookApp = None - outlookAppProgram = None + logger.info('outlook application collected') return outlookApp + logger.info('outlook not connected') + outlookApp = None + outlookAppProgram = None + return outlookApp def loadFromPickle(picklePath): @@ -2759,9 +2429,6 @@ def dumpToPickle(data, picklePath): """dump the data to picklePath """ # print("dumpToPickle %s, %s"% (picklePath, len(data))) - if not data: - os.remove(picklePath) - return try: with open(picklePath, 'wb') as pp: pickle.dump(data, pp) @@ -2773,29 +2440,44 @@ def dumpToPickle(data, picklePath): def collection_iter(collection): for index in range(collection.Count): yield collection.Item(index) - # standard stuff Joel (adapted for possible empty gramSpec, QH, unimacro) -thisGrammar = ThisGrammar() -if thisGrammar.gramSpec: - thisGrammar.initialize() -else: - thisGrammar = None + +# standard stuff Joel (adapted for different calling methods, including tests QH, unimacro) def unload(): - global thisGrammar, dialogGrammar - print("function unload in _folders.py") + #pylint:disable=W0603 + global thisGrammar + # print("function unload in _folders.py") if thisGrammar: - print("unloading folders grammar") - natlink.setTimerCallback(None, 0) - # make recentfoldersDict persistf across - try: - thisGrammar.dumpRecentFoldersDict() - except: - pass + # print("unloading folders grammar") + thisGrammar.stopRecentFolders() # stopping the timer callback thisGrammar.unload() - print("unloaded folders grammar") - time.sleep(5) - - thisGrammar = None + logger.info("unloaded folders grammar") + thisGrammar = None if __name__ == "__main__": - print(get_selected_files()) + ## interactive use, for debugging: + with natlink.natConnect(): + try: + thisGrammar = ThisGrammar(inifile_stem="_folders") + # thisGrammar.startInifile() + thisGrammar.initialize() + # print(thisGrammar.envvars) + # get hndle of a explore window (via _general "give window info") and try interactive + # thisGrammar.catchTimerRecentFolders(132524, "CabinetWClass") + active_folder = thisGrammar.getActiveFolder(198434) + print(f'active_folder: {active_folder}') + thisGrammar.displayRecentFolders() + # get hndle of a explore window (via _general "give window info") and try interactive + # thisGrammar.catchTimerRecentFolders(132524, "CabinetWClass") + + # # Words = ['folder', 'dtactions'] + # Fr = {} + # Words = ['subfolder', 'hello'] + # thisGrammar.gotResultsInit(Words, Fr) + # thisGrammar.gotResults_subfolder(Words, Fr) + finally: + thisGrammar.unload() +elif __name__.find('.') == -1: + # standard startup when Dragon starts: + thisGrammar = ThisGrammar() + thisGrammar.initialize() diff --git a/src/unimacro/UnimacroGrammars/_general.py b/src/unimacro/UnimacroGrammars/_general.py index 17287f7..735c6af 100644 --- a/src/unimacro/UnimacroGrammars/_general.py +++ b/src/unimacro/UnimacroGrammars/_general.py @@ -1,40 +1,42 @@ +# This was the old "general" intro for all unimacro grammar files: # This file is part of a SourceForge project called "unimacro" see # http://unimacro.SourceForge.net and http://qh.antenna.nl/unimacro # (c) copyright 2003 see http://qh.antenna.nl/unimacro/aboutunimacro.html # or the file COPYRIGHT.txt in the natlink\natlink directory # -# _general.PY +# _general.py # # written by Quintijn Hoogenboom (QH softwaretraining & advies), -# developed during the past few years. # # -"""do a set of general commands, with language versions possible, version 7 - -a lot of commands from the previous version removed, inserted a search and dictate -mode, that only works when spell mode or command mode is on. +#pylint:disable=C0302, R0904, C0209, C0321, R0912, R0914, R0915, R0911 +#pylint:disable=E1101 +"""do a set of general commands """ import re import os import sys +import time import pprint +from pathlib import Path -import utilsqh +import win32gui import natlink -import natlinkstatus -import win32gui -import namelist # for name phrases -import nsformat - -import natlinkutils as natut -from unimacro import natlinkutilsqh as natqh -import unimacro.natlinkutilsbj as natbj -from actions import doAction as action -from actions import doKeystroke as keystroke -import actions +from natlinkcore import natlinkstatus +from natlinkcore import nsformat +from natlinkcore import natlinkutils as natut +from natlinkcore import natlinktimer +from unimacro import natlinkutilsbj as natbj +from unimacro import namelist # for name phrases + +from dtactions.unimacro.unimacroactions import doAction as action +from dtactions.unimacro.unimacroactions import doKeystroke as keystroke +from dtactions.unimacro import unimacroactions as actions +from dtactions.unimacro import unimacroutils + # taskswitching moved to _tasks.py (july 2006) Counts = list(range(1,20)) + list(range(20,51,5)) @@ -45,31 +47,29 @@ systrayHndle = 0 status = natlinkstatus.NatlinkStatus() -language = status.getLanguage() +language = status.language FORMATS = { # for letters (do nothing): - 'no spacing': (natqh.wf_NoSpaceFollowingThisWord | natqh.wf_NoSpacePreceedingThisWord | - natqh.wf_TurnOffSpacingBetweenWords | - natqh.wf_DoNotApplyFormattingToThisWord + 'no spacing': (unimacroutils.wf_NoSpaceFollowingThisWord | unimacroutils.wf_NoSpacePreceedingThisWord | + unimacroutils.wf_TurnOffSpacingBetweenWords | + unimacroutils.wf_DoNotApplyFormattingToThisWord ), # normal words: - 'normal words': ( natqh.wf_RestoreNormalCapitalization | - natqh.wf_RestoreNormalSpacing + 'normal words': ( unimacroutils.wf_RestoreNormalCapitalization | + unimacroutils.wf_RestoreNormalSpacing ), # extra space(do one space): - 'extra space': ( natqh.wf_RestoreNormalCapitalization | - natqh.wf_RestoreNormalSpacing | - natqh.wf_AddAnExtraSpaceFollowingThisWord + 'extra space': ( unimacroutils.wf_RestoreNormalCapitalization | + unimacroutils.wf_RestoreNormalSpacing | + unimacroutils.wf_AddAnExtraSpaceFollowingThisWord ), } -version = status.getDNSVersion() -user = status.getUserName() -wordsFolder = os.path.split( - sys.modules[__name__].__dict__['__file__'])[0] + \ - '\\' + language + "_words" + \ - '\\' + user -utilsqh.createFolderIfNotExistent(wordsFolder) +user = status.user +unimacro_user_dir = status.getUnimacroUserDirectory() +wordsFolder = f'{unimacro_user_dir}\\{language}_words' +if not Path(wordsFolder).is_dir(): + Path(wordsFolder).mkdir() files = [os.path.splitext(f)[0] for f in os.listdir(wordsFolder)] ## print '_general, files in wordsFolder %s: %s'% (wordsFolder, files) @@ -94,15 +94,15 @@ "{Right}": "{Left}"} modes = ['spell', 'command', 'numbers', 'normal', 'dictation', 'dictate'] -normalSet = ['test', 'reload', 'info', 'undo', 'redo', 'namephrase', 'batch', +normalSet = ['test', 'reload', 'info', 'undo', 'redo', 'namephrase', 'comment', 'documentation', 'modes', 'variable', 'search', 'highlight', # for Shane, enable, because Vocola did not fix _anything yet 'browsewith', 'hyphenatephrase', 'pastepart', - 'password', 'presscode', 'choose'] + 'password', 'choose'] #normalSet = ['hyphenatephrase'] # skip 'openuser' commandSet = normalSet[:] + ['dictate'] - +thisGrammar = None ancestor=natbj.IniGrammar class ThisGrammar(ancestor): @@ -110,7 +110,7 @@ class ThisGrammar(ancestor): iniIgnoreGrammarLists = ['modes','count', 'namelist', 'character', 'punctuation'] - language = natqh.getLanguage() + language = unimacroutils.getLanguage() try: number_rules = natbj.numberGrammar[language] # including millions @@ -124,17 +124,10 @@ class ThisGrammar(ancestor): imported; # imported; exported = Make documentation; - exported = do batch words; exported = test micstate; - exported = (press|address) (|); exported = choose {n1-10}; -#test (klik|dubbelklik|shiftklik|controlklik|rechtsklik|foutklik|combinedklik|trippelklik); -# exported = test clipboard formats; -# exported = eating