├── pyautocore ├── pythonutil.cpp ├── pyautocore.def ├── kbhook.h ├── mousehook.h ├── clipboard.h ├── pythonutil.h ├── makefile.mingw ├── pyautocore.h ├── clipboard.cpp ├── kbhook.cpp ├── mousehook.cpp ├── pyautocore.vcxproj └── pyautocore.cpp ├── doc ├── image │ └── mailaddress.png ├── footer.html ├── index.txt └── pyauto.py ├── __init__.py ├── appveyor.yml ├── sample ├── monitor │ └── monitor.py ├── shellexecute │ └── shellexecute.py ├── keymap │ ├── keymap.py │ ├── keymap_config.py │ ├── keymap_hook.py │ └── config.py ├── mouse │ └── mouse.py ├── window_enum │ └── window_enum.py ├── hook │ └── hook.py ├── key │ └── key.py ├── image │ └── image.py ├── window_dump │ └── window_dump.py ├── window_message │ └── window_message.py └── window_resize │ └── window_resize.py ├── .gitignore ├── LICENSE.md ├── pyauto.sln ├── tool ├── rst2html_pygments.py └── rst2html_pygments.css ├── makefile.py ├── pyauto_input.py └── pyauto_const.py /pyautocore/pythonutil.cpp: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /pyautocore/pyautocore.def: -------------------------------------------------------------------------------- 1 | LIBRARY pyautocore.pyd 2 | EXPORTS 3 | initpyautocore@0 4 | -------------------------------------------------------------------------------- /doc/image/mailaddress.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/crftwr/pyauto/HEAD/doc/image/mailaddress.png -------------------------------------------------------------------------------- /pyautocore/kbhook.h: -------------------------------------------------------------------------------- 1 | #ifndef KBHOOK_H 2 | #define KBHOOK_H 3 | 4 | extern void HookStart_Key(); 5 | extern void HookEnd_Key(); 6 | 7 | #endif//KBHOOK_H 8 | -------------------------------------------------------------------------------- /__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf_8 -*- 2 | 3 | from pyauto.pyautocore import * 4 | from pyauto.pyauto_input import * 5 | from pyauto.pyauto_const import * 6 | 7 | -------------------------------------------------------------------------------- /pyautocore/mousehook.h: -------------------------------------------------------------------------------- 1 | #ifndef MOUSEHOOK_H 2 | #define MOUSEHOOK_H 3 | 4 | extern void HookStart_Mouse(); 5 | extern void HookEnd_Mouse(); 6 | 7 | #endif//MOUSEHOOK_H 8 | -------------------------------------------------------------------------------- /doc/footer.html: -------------------------------------------------------------------------------- 1 |
2 | Copyright © 2018 craftware. All rights reserved.
3 |
4 | 5 | 6 | -------------------------------------------------------------------------------- /pyautocore/clipboard.h: -------------------------------------------------------------------------------- 1 | #ifndef CLIPBOARD_H 2 | #define CLIPBOARD_H 3 | 4 | extern void HookStart_Clipboard(); 5 | extern void HookEnd_Clipboard(); 6 | extern LRESULT Hook_Clipboard_wndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam); 7 | 8 | #endif//CLIPBOARD_H 9 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | platform: 2 | # - x64 3 | - x86 4 | 5 | install: 6 | - MSBuild.exe pyauto.sln /target:Build /property:Configuration=Release,Platform=Win32 7 | - cinst -y doxygen.install 8 | - python makefile.py 9 | 10 | build: off 11 | test: off 12 | deploy: off 13 | -------------------------------------------------------------------------------- /sample/monitor/monitor.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf_8 -*- 2 | 3 | import os 4 | import sys 5 | 6 | sys.path[0:0] = [ 7 | os.path.abspath( os.path.join( os.path.split(sys.argv[0])[0], '../../..' ) ), 8 | ] 9 | 10 | import pyauto 11 | 12 | print( pyauto.Window.getMonitorInfo() ) 13 | 14 | -------------------------------------------------------------------------------- /sample/shellexecute/shellexecute.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | import time 4 | 5 | sys.path[0:0] = [ 6 | os.path.abspath( os.path.join( os.path.split(sys.argv[0])[0], '../../..' ) ), 7 | ] 8 | 9 | import pyauto 10 | 11 | pyauto.shellExecute( None, 12 | r"c:\windows\system32\notepad.exe", 13 | r"", 14 | r"", 15 | None ) 16 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | __pycache__ 2 | doc/html/ 3 | dist/ 4 | pyautocore/Debug/ 5 | pyautocore/Release/ 6 | Debug/ 7 | Release/ 8 | make.vcxproj.user 9 | pyauto.sdf 10 | pyauto.suo 11 | pyauto.v12.suo 12 | pyautocore.exp 13 | pyautocore.lib 14 | pyautocore.pdb 15 | pyautocore/pyautocore.vcxproj.user 16 | tags 17 | pyautocore_d.pyd 18 | pyauto.VC.opendb 19 | pyautocore.pyd 20 | pyautocore.ipdb 21 | pyautocore.iobj 22 | .vs/ 23 | *.ilk 24 | -------------------------------------------------------------------------------- /sample/keymap/keymap.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf_8 -*- 2 | 3 | import os 4 | import sys 5 | 6 | sys.path[0:0] = [ 7 | os.path.abspath( os.path.join( os.path.split(sys.argv[0])[0], '../../..' ) ), 8 | ] 9 | 10 | from keymap_hook import * 11 | from keymap_config import * 12 | 13 | if __name__ == "__main__": 14 | 15 | import pyauto 16 | 17 | loadConfigFile() 18 | 19 | print( "-- keymap start --" ) 20 | 21 | pyauto.messageLoop() 22 | 23 | print( "-- keymap end --" ) 24 | -------------------------------------------------------------------------------- /sample/mouse/mouse.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | import time 4 | import math 5 | 6 | sys.path[0:0] = [ 7 | os.path.abspath( os.path.join( os.path.split(sys.argv[0])[0], '../../..' ) ), 8 | ] 9 | 10 | import pyauto 11 | 12 | for i in range(1000): 13 | 14 | x = math.cos( i*0.01 ) * 200 + 300 15 | y = math.sin( i*0.01 ) * 200 + 300 16 | 17 | pyauto.Input.send([ 18 | 19 | pyauto.MouseMove( int(x), int(y) ), 20 | 21 | ]) 22 | 23 | time.sleep( 0.001 ) 24 | 25 | -------------------------------------------------------------------------------- /sample/keymap/keymap_config.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf_8 -*- 2 | 3 | user_namespace = {} 4 | 5 | def loadConfigFile(): 6 | 7 | filepath = 'config.py' 8 | 9 | try: 10 | print( "-- keymap config --" ) 11 | fd = open( filepath, 'r', encoding="utf-8" ) 12 | fileimage = fd.read() 13 | except IOError: 14 | print( 'ERROR : no config file.' ) 15 | 16 | try: 17 | code = compile( fileimage, filepath, 'exec' ) 18 | exec( code, user_namespace, user_namespace ) 19 | except SyntaxError as e: 20 | print( e ) 21 | -------------------------------------------------------------------------------- /sample/window_enum/window_enum.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf_8 -*- 2 | 3 | import os 4 | import sys 5 | 6 | sys.path[0:0] = [ 7 | os.path.abspath( os.path.join( os.path.split(sys.argv[0])[0], '../../..' ) ), 8 | ] 9 | 10 | import pyauto 11 | 12 | wnd_found = None 13 | def for_each_window( wnd, arg ): 14 | global wnd_found 15 | if wnd.getText().find("メモ帳") >= 0: 16 | wnd_found = wnd 17 | return False 18 | else: 19 | return True 20 | 21 | pyauto.Window.enum( for_each_window, None ) 22 | 23 | if wnd_found: 24 | wnd_found.setRect( (0,0,640,480) ) 25 | 26 | -------------------------------------------------------------------------------- /sample/hook/hook.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf_8 -*- 2 | 3 | import os 4 | import sys 5 | 6 | sys.path[0:0] = [ 7 | os.path.abspath( os.path.join( os.path.split(sys.argv[0])[0], '../../..' ) ), 8 | ] 9 | 10 | import pyauto 11 | 12 | hook = pyauto.Hook() 13 | 14 | def onKeyDown( vk, scan ): 15 | print( "onKeyDown : ", vk ) 16 | 17 | def onKeyUp( vk, scan ): 18 | print( "onKeyUp : ", vk ) 19 | 20 | def onClipboardChanged(): 21 | print( "onClipboardChanged" ) 22 | 23 | hook.keydown = onKeyDown 24 | hook.keyup = onKeyUp 25 | hook.clipboard = onClipboardChanged 26 | 27 | pyauto.messageLoop() 28 | 29 | -------------------------------------------------------------------------------- /sample/key/key.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf_8 -*- 2 | 3 | import os 4 | import sys 5 | 6 | sys.path[0:0] = [ 7 | os.path.abspath( os.path.join( os.path.split(sys.argv[0])[0], '../../..' ) ), 8 | ] 9 | 10 | import pyauto 11 | 12 | print( 'send ABC亜意鵜絵緒' ) 13 | 14 | pyauto.Input.send([ 15 | 16 | pyauto.KeyDown(pyauto.VK_SHIFT), 17 | 18 | pyauto.Key(ord('A')), 19 | pyauto.Key(ord('B')), 20 | pyauto.Key(ord('C')), 21 | 22 | pyauto.KeyUp(pyauto.VK_SHIFT), 23 | 24 | pyauto.Char(ord('亜')), 25 | pyauto.Char(ord('意')), 26 | pyauto.Char(ord('鵜')), 27 | pyauto.Char(ord('絵')), 28 | pyauto.Char(ord('緒')), 29 | 30 | ]) 31 | -------------------------------------------------------------------------------- /sample/image/image.py: -------------------------------------------------------------------------------- 1 | 2 | import os 3 | import sys 4 | 5 | sys.path[0:0] = [ 6 | os.path.abspath( os.path.join( os.path.split(sys.argv[0])[0], '../../..' ) ), 7 | ] 8 | 9 | import pyauto 10 | 11 | from PIL import Image 12 | 13 | 14 | root = pyauto.Window.getDesktop() 15 | 16 | image = root.getImage() 17 | 18 | print( "save desktop image as capture.png" ) 19 | print( " size:", image.getSize() ) 20 | print( " mode:", image.getMode() ) 21 | 22 | pil_image = Image.frombytes( image.getMode(), image.getSize(), image.getBuffer() ) 23 | pil_image.save( "capture.png" ) 24 | 25 | if 0: 26 | pil_icon = Image.open( "vcicon.png" ).convert("RGB") 27 | icon = pyauto.Image.fromString( pil_icon.mode, pil_icon.size, pil_icon.tobytes() ) 28 | 29 | icon_pos = image.find( icon ) 30 | print( "icon_pos:", icon_pos ) 31 | -------------------------------------------------------------------------------- /pyautocore/pythonutil.h: -------------------------------------------------------------------------------- 1 | #ifndef _PYTHONUTIL_H_ 2 | #define _PYTHONUTIL_H_ 3 | 4 | #if defined(_DEBUG) 5 | #undef _DEBUG 6 | #include "python.h" 7 | #define _DEBUG 8 | #else 9 | #include "python.h" 10 | #endif 11 | 12 | namespace PythonUtil 13 | { 14 | //#define GIL_Ensure_TRACE printf("%s(%d) : %s\n",__FILE__,__LINE__,__FUNCTION__) 15 | #define GIL_Ensure_TRACE 16 | 17 | class GIL_Ensure 18 | { 19 | public: 20 | GIL_Ensure() 21 | { 22 | GIL_Ensure_TRACE; 23 | state = PyGILState_Ensure(); 24 | GIL_Ensure_TRACE; 25 | }; 26 | 27 | ~GIL_Ensure() 28 | { 29 | GIL_Ensure_TRACE; 30 | PyGILState_Release(state); 31 | GIL_Ensure_TRACE; 32 | }; 33 | 34 | private: 35 | PyGILState_STATE state; 36 | }; 37 | 38 | #define PythonUtil_Printf(...) PySys_WriteStdout(__VA_ARGS__) 39 | #define PythonUtil_DebugPrintf(...) if(g.debug) { PySys_WriteStdout(__VA_ARGS__); } 40 | }; 41 | 42 | #endif // _PYTHONUTIL_H_ 43 | -------------------------------------------------------------------------------- /sample/window_dump/window_dump.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf_8 -*- 2 | 3 | import os 4 | import sys 5 | 6 | sys.path[0:0] = [ 7 | os.path.abspath( os.path.join( os.path.split(sys.argv[0])[0], '../../..' ) ), 8 | ] 9 | 10 | import pyauto 11 | 12 | def dump( wnd, indent ): 13 | if not wnd: return 14 | 15 | if wnd.isVisible() and not wnd.isMinimized(): 16 | 17 | def Window_getProcessName(wnd): 18 | try: 19 | return wnd.getProcessName() 20 | except: 21 | return "(error)" 22 | 23 | print( "%s%s:%s:%s%s" % ( " " * indent, Window_getProcessName(wnd), wnd.getText(), wnd.getClassName(), wnd.getRect() ) ) 24 | 25 | child = wnd.getFirstChild() 26 | 27 | while child: 28 | 29 | dump( child, indent + 4 ) 30 | 31 | child = child.getNext() 32 | 33 | 34 | root = pyauto.Window.getDesktop() 35 | 36 | dump(root,0) 37 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 craftware 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /pyauto.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.13.35806.99 d17.13 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pyautocore", "pyautocore\pyautocore.vcxproj", "{2D8BB990-8905-4DCF-8811-3F97A27BED1A}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|x64 = Debug|x64 11 | Release|x64 = Release|x64 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {2D8BB990-8905-4DCF-8811-3F97A27BED1A}.Debug|x64.ActiveCfg = Debug|x64 15 | {2D8BB990-8905-4DCF-8811-3F97A27BED1A}.Debug|x64.Build.0 = Debug|x64 16 | {2D8BB990-8905-4DCF-8811-3F97A27BED1A}.Release|x64.ActiveCfg = Release|x64 17 | {2D8BB990-8905-4DCF-8811-3F97A27BED1A}.Release|x64.Build.0 = Release|x64 18 | EndGlobalSection 19 | GlobalSection(SolutionProperties) = preSolution 20 | HideSolutionNode = FALSE 21 | EndGlobalSection 22 | GlobalSection(ExtensibilityGlobals) = postSolution 23 | SolutionGuid = {D2C4BE9C-7E83-46FB-8B5C-298782D7CB3D} 24 | EndGlobalSection 25 | EndGlobal 26 | -------------------------------------------------------------------------------- /pyautocore/makefile.mingw: -------------------------------------------------------------------------------- 1 | TARGET = pyautocore.pyd 2 | 3 | PYTHON_DIR ?= c:/python27 4 | 5 | SRCS = $(wildcard *.cpp) 6 | OBJS = $(SRCS:%.cpp=%.o) 7 | MDS = $(SRCS:%.cpp=%.d) 8 | 9 | ifeq ($(BUILD_MODE),debug) 10 | BUILD_MODE_CFLAGS = \ 11 | -g -DDEBUG 12 | else 13 | BUILD_MODE_CFLAGS = \ 14 | -O2 -DNDEBUG 15 | endif 16 | 17 | CFLAGS = \ 18 | $(BUILD_MODE_CFLAGS) \ 19 | -MD \ 20 | -fno-common \ 21 | -fno-exceptions \ 22 | -fno-rtti \ 23 | -I$(PYTHON_DIR)/include \ 24 | -DWINVER=0x0500 \ 25 | -D_WIN32_WINNT=0x0500 \ 26 | -D_UNICODE=1 \ 27 | -DUNICODE=1 \ 28 | 29 | LIBS = \ 30 | -L$(PYTHON_DIR)/libs \ 31 | -lpython27 \ 32 | -lgdi32 \ 33 | -limm32 \ 34 | 35 | #------------------------------------------------------------------- 36 | 37 | all: $(TARGET) 38 | 39 | clean: 40 | rm -f $(OBJS) $(MDS) $(TARGET) *~ 41 | 42 | #------------------------------------------------------------------- 43 | 44 | .SUFFIXES: .exe .pyd .o .cpp 45 | 46 | .cpp.o: 47 | g++ $(CFLAGS) -o $@ -c $< 48 | 49 | $(TARGET): $(OBJS) 50 | dllwrap --target=i386-mingw32 -static -static-libgcc -k -def pyautocore.def --driver-name g++ -o $@ $(OBJS) $(LIBS) 51 | strip $@ 52 | 53 | #------------------------------------------------------------------- 54 | 55 | -include $(MDS) 56 | -------------------------------------------------------------------------------- /pyautocore/pyautocore.h: -------------------------------------------------------------------------------- 1 | #ifndef PYAUTOCORE_H 2 | #define PYAUTOCORE_H 3 | 4 | 5 | namespace pyauto 6 | { 7 | extern PyTypeObject PyType_Window; 8 | 9 | struct PyObject_Window 10 | { 11 | PyObject_HEAD 12 | HWND hwnd; 13 | }; 14 | 15 | extern PyTypeObject PyType_Image; 16 | 17 | struct PyObject_Image 18 | { 19 | PyObject_HEAD 20 | int w; 21 | int h; 22 | void * buf; 23 | unsigned int bufsize; 24 | }; 25 | 26 | extern PyTypeObject PyType_Input; 27 | 28 | struct PyObject_Input 29 | { 30 | PyObject_HEAD 31 | int num; 32 | INPUT input[2]; 33 | }; 34 | 35 | extern PyTypeObject PyType_Hook; 36 | 37 | struct PyObject_Hook 38 | { 39 | PyObject_HEAD 40 | 41 | PyObject * keydown; 42 | PyObject * keyup; 43 | 44 | PyObject * mousedown; 45 | PyObject * mouseup; 46 | PyObject * mousedblclk; 47 | PyObject * mousemove; // FIXME : not implemented 48 | PyObject * mousewheel; 49 | PyObject * mousehorizontalwheel; 50 | 51 | PyObject * clipboard; 52 | }; 53 | 54 | struct Globals 55 | { 56 | HMODULE module_handle; 57 | PyObject * Error; 58 | PyObject_Hook * pyhook; 59 | HWND pyauto_window; 60 | DWORD last_key_time; 61 | bool debug; 62 | }; 63 | 64 | extern Globals g; 65 | }; 66 | 67 | #define TypeCheck_Window(op) PyObject_TypeCheck(op, &PyType_Window) 68 | #define TypeCheck_Image(op) PyObject_TypeCheck(op, &PyType_Image) 69 | #define TypeCheck_Input(op) PyObject_TypeCheck(op, &PyType_Input) 70 | #define TypeCheck_Hook(op) PyObject_TypeCheck(op, &PyType_Hook) 71 | 72 | 73 | #endif//PYAUTOCORE_H 74 | -------------------------------------------------------------------------------- /pyautocore/clipboard.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | #include "pythonutil.h" 6 | #include "pyautocore.h" 7 | 8 | using namespace pyauto; 9 | 10 | static bool clipboard_hook_installed; 11 | 12 | LRESULT Hook_Clipboard_wndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) 13 | { 14 | switch(message) 15 | { 16 | case WM_CLIPBOARDUPDATE: 17 | { 18 | //PythonUtil_DebugPrintf("WM_CLIPBOARDUPDATE\n"); 19 | 20 | static bool enter = false; 21 | if(!enter) 22 | { 23 | enter = true; 24 | 25 | if(g.pyhook && g.pyhook->clipboard) 26 | { 27 | PyObject * pyarglist = Py_BuildValue("()"); 28 | PyObject * pyresult = PyObject_Call( g.pyhook->clipboard, pyarglist, NULL ); 29 | Py_DECREF(pyarglist); 30 | if(pyresult) 31 | { 32 | Py_DECREF(pyresult); 33 | } 34 | else 35 | { 36 | PyErr_Print(); 37 | } 38 | } 39 | 40 | enter = false; 41 | } 42 | else 43 | { 44 | PythonUtil_DebugPrintf("WM_CLIPBOARDUPDATE nested!\n"); 45 | } 46 | } 47 | break; 48 | } 49 | 50 | return 0; 51 | } 52 | 53 | void HookStart_Clipboard() 54 | { 55 | //printf("HookStart_Clipboard\n"); 56 | 57 | if (!clipboard_hook_installed) 58 | { 59 | if (AddClipboardFormatListener(g.pyauto_window)) 60 | { 61 | clipboard_hook_installed = true; 62 | } 63 | else 64 | { 65 | PythonUtil_DebugPrintf("AddClipboardFormatListener() failed : %x\n", GetLastError()); 66 | } 67 | } 68 | } 69 | 70 | void HookEnd_Clipboard() 71 | { 72 | //printf("HookEnd_Clipboard\n"); 73 | 74 | if (clipboard_hook_installed) 75 | { 76 | if (RemoveClipboardFormatListener(g.pyauto_window)) 77 | { 78 | clipboard_hook_installed = false; 79 | } 80 | else 81 | { 82 | PythonUtil_DebugPrintf("RemoveClipboardFormatListener() failed : %x\n", GetLastError()); 83 | } 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /tool/rst2html_pygments.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | # :Author: David Goodger, the Pygments team, Guenter Milde 4 | # :Date: $Date: $ 5 | # :Copyright: This module has been placed in the public domain. 6 | 7 | # This is a merge of the docutils_ `rst2html` front end with an extension 8 | # suggestion taken from the pygments_ documentation. 9 | 10 | """ 11 | A front end to docutils, producing HTML with syntax colouring using pygments 12 | """ 13 | 14 | try: 15 | import locale 16 | locale.setlocale(locale.LC_ALL, '') 17 | except: 18 | pass 19 | 20 | from docutils.core import publish_cmdline, default_description 21 | 22 | description = ('Generates (X)HTML documents from standalone reStructuredText ' 23 | 'sources. Uses `pygments` to colorize the content of' 24 | '"code-block" directives. Needs an adapted stylesheet' 25 | + default_description) 26 | 27 | # Define a new directive `code-block` that uses the `pygments` source 28 | # highlighter to render code in color. 29 | # 30 | # Code from the `pygments`_ documentation for `Using Pygments in ReST 31 | # documents`_. 32 | 33 | from docutils import nodes 34 | from docutils.parsers.rst import directives 35 | from pygments import highlight 36 | from pygments.lexers import get_lexer_by_name 37 | from pygments.formatters import HtmlFormatter 38 | 39 | pygments_formatter = HtmlFormatter() 40 | 41 | def pygments_directive(name, arguments, options, content, lineno, 42 | content_offset, block_text, state, state_machine): 43 | try: 44 | lexer = get_lexer_by_name(arguments[0]) 45 | except ValueError: 46 | # no lexer found - use the text one instead of an exception 47 | lexer = get_lexer_by_name('text') 48 | parsed = highlight(u'\n'.join(content), lexer, pygments_formatter) 49 | return [nodes.raw('', parsed, format='html')] 50 | pygments_directive.arguments = (1, 0, 1) 51 | pygments_directive.content = 1 52 | directives.register_directive('code-block', pygments_directive) 53 | 54 | # Call the docutils publisher to render the input as html:: 55 | 56 | publish_cmdline(writer_name='html', description=description) 57 | 58 | # .. _doctutile: http://docutils.sf.net/ 59 | # .. _pygments: http://pygments.org/ 60 | # .. _Using Pygments in ReST documents: http://pygments.org/docs/rstdirective/ 61 | -------------------------------------------------------------------------------- /sample/window_message/window_message.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | import time 4 | 5 | sys.path[0:0] = [ 6 | os.path.abspath( os.path.join( os.path.split(sys.argv[0])[0], '../../..' ) ), 7 | ] 8 | 9 | import pyauto 10 | 11 | wnd = pyauto.Window.find( "Notepad", None ) 12 | 13 | if not wnd: 14 | pyauto.shellExecute( None, r"c:\windows\system32\notepad.exe" ) 15 | while not wnd: 16 | wnd = pyauto.Window.find( "Notepad", None ) 17 | time.sleep(1) 18 | 19 | if wnd: 20 | 21 | if 0: 22 | 23 | time.sleep(1) 24 | 25 | print( 'WM_SYSCOMMAND, SC_MAXIMIZE' ) 26 | wnd.sendMessage( pyauto.WM_SYSCOMMAND, pyauto.SC_MAXIMIZE ) 27 | 28 | time.sleep(1) 29 | 30 | print( 'WM_SYSCOMMAND, SC_MINIMIZE' ) 31 | wnd.sendMessage( pyauto.WM_SYSCOMMAND, pyauto.SC_MINIMIZE ) 32 | 33 | time.sleep(1) 34 | 35 | print( 'WM_SYSCOMMAND, SC_RESTORE' ) 36 | wnd.sendMessage( pyauto.WM_SYSCOMMAND, pyauto.SC_RESTORE ) 37 | 38 | time.sleep(1) 39 | 40 | print( 'WM_SYSCOMMAND, SC_CLOSE' ) 41 | wnd.sendMessage( pyauto.WM_SYSCOMMAND, pyauto.SC_CLOSE ) 42 | 43 | 44 | elif 0: 45 | 46 | time.sleep(1) 47 | 48 | print( 'WM_SYSCOMMAND, SC_SIZE' ) 49 | wnd.sendMessage( pyauto.WM_SYSCOMMAND, pyauto.SC_SIZE ) 50 | 51 | print( 'WM_SYSCOMMAND, SC_MOVE' ) 52 | wnd.sendMessage( pyauto.WM_SYSCOMMAND, pyauto.SC_MOVE ) 53 | 54 | print( 'WM_SYSCOMMAND, SC_CONTEXTHELP' ) 55 | wnd.sendMessage( pyauto.WM_SYSCOMMAND, pyauto.SC_CONTEXTHELP ) 56 | 57 | print( 'WM_SYSCOMMAND, SC_NEXTWINDOW' ) 58 | wnd.sendMessage( pyauto.WM_SYSCOMMAND, pyauto.SC_NEXTWINDOW ) 59 | 60 | 61 | elif 0: 62 | 63 | time.sleep(1) 64 | 65 | print( 'WM_SYSCOMMAND, SC_MOUSEMENU' ) 66 | wnd.sendMessage( pyauto.WM_SYSCOMMAND, pyauto.SC_MOUSEMENU ) 67 | 68 | time.sleep(1) 69 | 70 | print( 'WM_SYSCOMMAND, SC_KEYMENU' ) 71 | wnd.sendMessage( pyauto.WM_SYSCOMMAND, pyauto.SC_KEYMENU ) 72 | 73 | elif 1: 74 | 75 | time.sleep(1) 76 | 77 | print( 'WM_SYSCOMMAND, SC_TASKLIST' ) 78 | wnd.sendMessage( pyauto.WM_SYSCOMMAND, pyauto.SC_TASKLIST ) 79 | 80 | time.sleep(1) 81 | 82 | print( 'WM_SYSCOMMAND, SC_SCREENSAVE' ) 83 | wnd.sendMessage( pyauto.WM_SYSCOMMAND, pyauto.SC_SCREENSAVE ) 84 | 85 | time.sleep(1) 86 | 87 | print( 'WM_SYSCOMMAND, SC_MONITORPOWER' ) 88 | wnd.sendMessage( pyauto.WM_SYSCOMMAND, pyauto.SC_MONITORPOWER, 2 ) 89 | 90 | 91 | elif 0: 92 | 93 | time.sleep(1) 94 | 95 | print( 'WM_SYSCOMMAND, SC_HOTKEY' ) 96 | wnd.sendMessage( pyauto.WM_SYSCOMMAND, pyauto.SC_HOTKEY ) 97 | 98 | time.sleep(1) 99 | 100 | print( 'WM_SYSCOMMAND, SC_DEFAULT' ) 101 | wnd.sendMessage( pyauto.WM_SYSCOMMAND, pyauto.SC_DEFAULT ) 102 | 103 | -------------------------------------------------------------------------------- /makefile.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | import subprocess 4 | import shutil 5 | import zipfile 6 | import hashlib 7 | 8 | DIST_DIR = "dist/pyauto" 9 | DIST_SRC_DIR = "dist/src" 10 | 11 | PYTHON_DIR = "c:/Python37" 12 | PYTHON = PYTHON_DIR + "/python.exe" 13 | SVN_DIR = "c:/Program Files/TortoiseSVN/bin" 14 | DOXYGEN_DIR = "c:/Program Files/doxygen" 15 | 16 | def unlink(filename): 17 | try: 18 | os.unlink(filename) 19 | except OSError: 20 | pass 21 | 22 | def makedirs(dirname): 23 | try: 24 | os.makedirs(dirname) 25 | except OSError: 26 | pass 27 | 28 | def rmtree(dirname): 29 | try: 30 | shutil.rmtree(dirname) 31 | except OSError: 32 | pass 33 | 34 | def createZip( zip_filename, items ): 35 | z = zipfile.ZipFile( zip_filename, "w", zipfile.ZIP_DEFLATED, True ) 36 | for item in items: 37 | if os.path.isdir(item): 38 | for root, dirs, files in os.walk(item): 39 | for f in files: 40 | f = os.path.join(root,f) 41 | print( f ) 42 | z.write(f) 43 | else: 44 | print( item ) 45 | z.write(item) 46 | z.close() 47 | 48 | DIST_FILES = [ 49 | "pyauto", 50 | ] 51 | 52 | def build(): 53 | doc() 54 | exe() 55 | 56 | def exe(): 57 | makedirs( DIST_DIR ) 58 | shutil.copy( "pyautocore.pyd", DIST_DIR ) 59 | shutil.copy( "__init__.py", DIST_DIR ) 60 | shutil.copy( "pyauto_const.py", DIST_DIR ) 61 | shutil.copy( "pyauto_input.py", DIST_DIR ) 62 | rmtree( DIST_DIR + "/sample" ) 63 | shutil.copytree( "sample", DIST_DIR + "/sample", ignore=shutil.ignore_patterns(".svn","*.pyc","*.pyo") ) 64 | rmtree( DIST_DIR + "/doc" ) 65 | shutil.copytree( "doc/html", DIST_DIR + "/doc", ignore=shutil.ignore_patterns(".svn") ) 66 | 67 | if 1: 68 | os.chdir("dist") 69 | createZip( "pyauto.zip", DIST_FILES ) 70 | os.chdir("..") 71 | 72 | fd = open("dist/pyauto.zip","rb") 73 | m = hashlib.md5() 74 | while 1: 75 | data = fd.read( 1024 * 1024 ) 76 | if not data: break 77 | m.update(data) 78 | fd.close() 79 | print( "" ) 80 | print( m.hexdigest() ) 81 | 82 | def rebuild(): 83 | clean() 84 | build() 85 | 86 | def clean(): 87 | rmtree("doc/html") 88 | unlink( "tags" ) 89 | 90 | def doc(): 91 | rmtree( "doc/html" ) 92 | makedirs( "doc/html" ) 93 | subprocess.call( [ DOXYGEN_DIR + "/bin/doxygen.exe", "doc/doxyfile" ] ) 94 | subprocess.call( [ PYTHON, "tool/rst2html_pygments.py", "--stylesheet=tool/rst2html_pygments.css", "doc/index.txt", "doc/html/index.html" ] ) 95 | shutil.copytree( "doc/image", "doc/html/image", ignore=shutil.ignore_patterns(".svn","*.pdn") ) 96 | 97 | if len(sys.argv)<=1: 98 | target = "build" 99 | else: 100 | target = sys.argv[1] 101 | 102 | eval( target + "()" ) 103 | 104 | -------------------------------------------------------------------------------- /pyautocore/kbhook.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | #include "pythonutil.h" 6 | #include "pyautocore.h" 7 | 8 | static HHOOK key_hook = NULL; 9 | 10 | using namespace pyauto; 11 | 12 | // WH_KEYBOARD_LL と SendInput の関係: 13 | // 14 | // KeyHookProc() のなかで SendInput() を呼び出すと、 15 | // KeyHookProc() がネストして呼び出される。 16 | // 17 | LRESULT CALLBACK KeyHookProc(int nCode, WPARAM wParam, LPARAM lParam) 18 | { 19 | PythonUtil::GIL_Ensure gil_ensure; 20 | 21 | if(nCode<0) 22 | { 23 | LRESULT result = CallNextHookEx(key_hook, nCode, wParam, lParam); 24 | return result; 25 | } 26 | 27 | KBDLLHOOKSTRUCT * pkbdllhook = (KBDLLHOOKSTRUCT*)lParam; 28 | 29 | // タイムスタンプが逆転してしまった場合は、予期しないことが起きている 30 | if( g.last_key_time > pkbdllhook->time ) 31 | { 32 | PythonUtil_Printf("Time stamp inversion happened.\n"); 33 | } 34 | 35 | // 自分の SendInput によって挿入されたキーイベントはスクリプトで処理しない。 36 | // vkCode==0 のイベントは特別扱いし、必ず Python で処理する。 37 | if( pkbdllhook->flags & LLKHF_INJECTED 38 | && pkbdllhook->dwExtraInfo == (ULONG_PTR)g.module_handle 39 | && pkbdllhook->vkCode ) 40 | { 41 | LRESULT result = CallNextHookEx(key_hook, nCode, wParam, lParam); 42 | return result; 43 | } 44 | 45 | switch(wParam) 46 | { 47 | case WM_KEYDOWN: 48 | case WM_SYSKEYDOWN: 49 | if(g.pyhook->keydown) 50 | { 51 | DWORD vk = pkbdllhook->vkCode; 52 | DWORD scan = pkbdllhook->scanCode; 53 | g.last_key_time = pkbdllhook->time; 54 | 55 | PyObject * pyarglist = Py_BuildValue("(ii)", vk, scan ); 56 | PyObject * pyresult = PyObject_Call( g.pyhook->keydown, pyarglist, NULL ); 57 | Py_DECREF(pyarglist); 58 | if(pyresult) 59 | { 60 | int result; 61 | if( pyresult==Py_None ) 62 | { 63 | result = 0; 64 | } 65 | else 66 | { 67 | PyArg_Parse(pyresult,"i", &result ); 68 | } 69 | Py_DECREF(pyresult); 70 | 71 | if(result) 72 | { 73 | return result; 74 | } 75 | } 76 | else 77 | { 78 | PyErr_Print(); 79 | } 80 | } 81 | break; 82 | 83 | case WM_KEYUP: 84 | case WM_SYSKEYUP: 85 | if(g.pyhook->keyup) 86 | { 87 | DWORD vk = pkbdllhook->vkCode; 88 | DWORD scan = pkbdllhook->scanCode; 89 | g.last_key_time = pkbdllhook->time; 90 | 91 | PyObject * pyarglist = Py_BuildValue("(ii)", vk, scan ); 92 | PyObject * pyresult = PyObject_Call( g.pyhook->keyup, pyarglist, NULL ); 93 | Py_DECREF(pyarglist); 94 | if(pyresult) 95 | { 96 | int result; 97 | if( pyresult==Py_None ) 98 | { 99 | result = 0; 100 | } 101 | else 102 | { 103 | PyArg_Parse(pyresult,"i", &result ); 104 | } 105 | Py_DECREF(pyresult); 106 | 107 | if(result) 108 | { 109 | return result; 110 | } 111 | } 112 | else 113 | { 114 | PyErr_Print(); 115 | } 116 | } 117 | break; 118 | } 119 | 120 | LRESULT result = CallNextHookEx(key_hook, nCode, wParam, lParam); 121 | return result; 122 | } 123 | 124 | void HookStart_Key() 125 | { 126 | if(!key_hook) 127 | { 128 | PythonUtil_DebugPrintf("SetWindowsHookEx\n" ); 129 | key_hook = SetWindowsHookEx( WH_KEYBOARD_LL, KeyHookProc, g.module_handle, 0 ); 130 | } 131 | 132 | if( key_hook==NULL ) 133 | { 134 | PythonUtil_DebugPrintf("SetWindowsHookEx failed : %x\n", GetLastError() ); 135 | } 136 | } 137 | 138 | void HookEnd_Key() 139 | { 140 | if(key_hook) 141 | { 142 | if( ! UnhookWindowsHookEx(key_hook) ) 143 | { 144 | PythonUtil_DebugPrintf("UnhookWindowsHookEx(key) failed\n"); 145 | } 146 | 147 | key_hook=NULL; 148 | } 149 | } 150 | -------------------------------------------------------------------------------- /sample/window_resize/window_resize.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | import time 4 | 5 | sys.path[0:0] = [ 6 | os.path.abspath( os.path.join( os.path.split(sys.argv[0])[0], '../../..' ) ), 7 | ] 8 | 9 | import pyauto 10 | 11 | wnd = pyauto.Window.find( "Notepad", None ) 12 | 13 | if not wnd: 14 | pyauto.shellExecute( None, r"c:\windows\system32\notepad.exe" ) 15 | while not wnd: 16 | wnd = pyauto.Window.find( "Notepad", None ) 17 | time.sleep(1) 18 | 19 | if wnd: 20 | 21 | rect = wnd.getRect() 22 | print( "rect:", rect ) 23 | rect = list(rect) 24 | for i in range(100): 25 | rect[0] += 1 26 | rect[1] += 1 27 | wnd.setRect( rect ) 28 | time.sleep(0.01) 29 | for i in range(100): 30 | rect[2] -= 1 31 | rect[3] -= 1 32 | wnd.setRect( rect ) 33 | time.sleep(0.01) 34 | rect = wnd.getRect() 35 | print( "rect:", rect ) 36 | 37 | if wnd.isMinimized(): print( "minimized", end="" ) 38 | if wnd.isMaximized(): print( "maximized", end="" ) 39 | if not wnd.isMinimized() and not wnd.isMaximized() : print( "normal", end="" ) 40 | print( "" ) 41 | 42 | time.sleep( 1 ) 43 | 44 | wnd.minimize() 45 | 46 | time.sleep( 1 ) 47 | 48 | if wnd.isMinimized(): print( "minimized", end="" ) 49 | if wnd.isMaximized(): print( "maximized", end="" ) 50 | if not wnd.isMinimized() and not wnd.isMaximized() : print( "normal", end="" ) 51 | print( "" ) 52 | 53 | time.sleep( 1 ) 54 | 55 | wnd.restore() 56 | 57 | time.sleep( 1 ) 58 | 59 | if wnd.isMinimized(): print( "minimized", end="" ) 60 | if wnd.isMaximized(): print( "maximized", end="" ) 61 | if not wnd.isMinimized() and not wnd.isMaximized() : print( "normal", end="" ) 62 | print( "" ) 63 | 64 | time.sleep( 1 ) 65 | 66 | wnd.maximize() 67 | 68 | time.sleep( 1 ) 69 | 70 | if wnd.isMinimized(): print( "minimized", end="" ) 71 | if wnd.isMaximized(): print( "maximized", end="" ) 72 | if not wnd.isMinimized() and not wnd.isMaximized() : print( "normal", end="" ) 73 | print( "" ) 74 | 75 | time.sleep( 1 ) 76 | 77 | wnd.restore() 78 | 79 | time.sleep( 1 ) 80 | 81 | if wnd.isMinimized(): print( "minimized", end="" ) 82 | if wnd.isMaximized(): print( "maximized", end="" ) 83 | if not wnd.isMinimized() and not wnd.isMaximized() : print( "normal", end="" ) 84 | print( "" ) 85 | 86 | time.sleep( 1 ) 87 | 88 | wnd.maximize() 89 | 90 | time.sleep( 1 ) 91 | 92 | if wnd.isMinimized(): print( "minimized", end="" ) 93 | if wnd.isMaximized(): print( "maximized", end="" ) 94 | if not wnd.isMinimized() and not wnd.isMaximized() : print( "normal", end="" ) 95 | print( "" ) 96 | 97 | time.sleep( 1 ) 98 | 99 | wnd.minimize() 100 | 101 | time.sleep( 1 ) 102 | 103 | if wnd.isMinimized(): print( "minimized", end="" ) 104 | if wnd.isMaximized(): print( "maximized", end="" ) 105 | if not wnd.isMinimized() and not wnd.isMaximized() : print( "normal", end="" ) 106 | print( "" ) 107 | 108 | time.sleep( 1 ) 109 | 110 | wnd.restore() 111 | 112 | time.sleep( 1 ) 113 | 114 | if wnd.isMinimized(): print( "minimized", end="" ) 115 | if wnd.isMaximized(): print( "maximized", end="" ) 116 | if not wnd.isMinimized() and not wnd.isMaximized() : print( "normal", end="" ) 117 | print( "" ) 118 | 119 | time.sleep( 1 ) 120 | 121 | wnd.restore() 122 | 123 | time.sleep( 1 ) 124 | 125 | if wnd.isMinimized(): print( "minimized", end="" ) 126 | if wnd.isMaximized(): print( "maximized", end="" ) 127 | if not wnd.isMinimized() and not wnd.isMaximized() : print( "normal", end="" ) 128 | print( "" ) 129 | 130 | -------------------------------------------------------------------------------- /pyauto_input.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf_8 -*- 2 | 3 | import pyauto.pyautocore as pyautocore 4 | 5 | ## @addtogroup pyauto 6 | ## @{ 7 | 8 | ## 仮想的なキーダウンを生成するクラス 9 | class KeyDown( pyautocore.Input ): 10 | 11 | def __init__( self, vk ): 12 | 13 | pyautocore.Input.__init__(self) 14 | if type(vk)==str and len(vk)==1 : vk=ord(vk) 15 | self.setKeyDown(vk) 16 | 17 | ## 仮想的なキーアップを生成するクラス 18 | class KeyUp( pyautocore.Input ): 19 | 20 | def __init__( self, vk ): 21 | 22 | pyautocore.Input.__init__(self) 23 | if type(vk)==str and len(vk)==1 : vk=ord(vk) 24 | self.setKeyUp(vk) 25 | 26 | ## 仮想的なキーのダウンとアップを生成するクラス 27 | class Key( pyautocore.Input ): 28 | 29 | def __init__( self, vk ): 30 | 31 | pyautocore.Input.__init__(self) 32 | if type(vk)==str and len(vk)==1 : vk=ord(vk) 33 | self.setKey(vk) 34 | 35 | ## 仮想的な文字入力を生成するクラス 36 | class Char( pyautocore.Input ): 37 | 38 | def __init__( self, c ): 39 | 40 | pyautocore.Input.__init__(self) 41 | if type(c)==str and len(c)==1 : c=ord(c) 42 | self.setChar(c) 43 | 44 | ## 仮想的なマウス移動を生成するクラス 45 | class MouseMove( pyautocore.Input ): 46 | 47 | def __init__( self, x, y ): 48 | 49 | pyautocore.Input.__init__(self) 50 | self.setMouseMove( x, y ) 51 | 52 | ## 仮想的なマウスの左ボタンダウンを生成するクラス 53 | class MouseLeftDown( pyautocore.Input ): 54 | 55 | def __init__( self, x, y ): 56 | 57 | pyautocore.Input.__init__(self) 58 | self.setMouseLeftDown( x, y ) 59 | 60 | ## 仮想的なマウスの左ボタンアップを生成するクラス 61 | class MouseLeftUp( pyautocore.Input ): 62 | 63 | def __init__( self, x, y ): 64 | 65 | pyautocore.Input.__init__(self) 66 | self.setMouseLeftUp( x, y ) 67 | 68 | ## 仮想的なマウスの左ボタンのダウンとアップを生成するクラス 69 | class MouseLeftClick( pyautocore.Input ): 70 | 71 | def __init__( self, x, y ): 72 | 73 | pyautocore.Input.__init__(self) 74 | self.setMouseLeftClick( x, y ) 75 | 76 | ## 仮想的なマウスの右ボタンダウンを生成するクラス 77 | class MouseRightDown( pyautocore.Input ): 78 | 79 | def __init__( self, x, y ): 80 | 81 | pyautocore.Input.__init__(self) 82 | self.setMouseRightDown( x, y ) 83 | 84 | ## 仮想的なマウスの右ボタンアップを生成するクラス 85 | class MouseRightUp( pyautocore.Input ): 86 | 87 | def __init__( self, x, y ): 88 | 89 | pyautocore.Input.__init__(self) 90 | self.setMouseRightUp( x, y ) 91 | 92 | ## 仮想的なマウスの右ボタンのダウンとアップを生成するクラス 93 | class MouseRightClick( pyautocore.Input ): 94 | 95 | def __init__( self, x, y ): 96 | 97 | pyautocore.Input.__init__(self) 98 | self.setMouseRightClick( x, y ) 99 | 100 | ## 仮想的なマウスの中ボタンダウンを生成するクラス 101 | class MouseMiddleDown( pyautocore.Input ): 102 | 103 | def __init__( self, x, y ): 104 | 105 | pyautocore.Input.__init__(self) 106 | self.setMouseMiddleDown( x, y ) 107 | 108 | ## 仮想的なマウスの中ボタンアップを生成するクラス 109 | class MouseMiddleUp( pyautocore.Input ): 110 | 111 | def __init__( self, x, y ): 112 | 113 | pyautocore.Input.__init__(self) 114 | self.setMouseMiddleUp( x, y ) 115 | 116 | ## 仮想的なマウスの中ボタンのダウンとアップを生成するクラス 117 | class MouseMiddleClick( pyautocore.Input ): 118 | 119 | def __init__( self, x, y ): 120 | 121 | pyautocore.Input.__init__(self) 122 | self.setMouseMiddleClick( x, y ) 123 | 124 | ## 仮想的なマウスのホイール回転を生成するクラス 125 | class MouseWheel( pyautocore.Input ): 126 | 127 | def __init__( self, x, y, wheel ): 128 | 129 | pyautocore.Input.__init__(self) 130 | self.setMouseWheel( x, y, wheel ) 131 | 132 | ## 仮想的なマウスの水平のホイール回転を生成するクラス 133 | class MouseHorizontalWheel( pyautocore.Input ): 134 | 135 | def __init__( self, x, y, wheel ): 136 | 137 | pyautocore.Input.__init__(self) 138 | self.setMouseHorizontalWheel( x, y, wheel ) 139 | 140 | ## @} pyauto 141 | 142 | -------------------------------------------------------------------------------- /pyautocore/mousehook.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | #include "pythonutil.h" 6 | #include "pyautocore.h" 7 | 8 | static HHOOK mouse_hook = NULL; 9 | 10 | using namespace pyauto; 11 | 12 | static int OnMouseButton( WPARAM wParam, MSLLHOOKSTRUCT * pmousellhook, PyObject * pyfunc ) 13 | { 14 | int result; 15 | 16 | g.last_key_time = pmousellhook->time; 17 | 18 | DWORD vk; 19 | switch(wParam) 20 | { 21 | case WM_LBUTTONDOWN: 22 | case WM_LBUTTONUP: 23 | case WM_LBUTTONDBLCLK: 24 | vk = VK_LBUTTON; 25 | break; 26 | case WM_RBUTTONDOWN: 27 | case WM_RBUTTONUP: 28 | case WM_RBUTTONDBLCLK: 29 | vk = VK_RBUTTON; 30 | break; 31 | case WM_MBUTTONDOWN: 32 | case WM_MBUTTONUP: 33 | case WM_MBUTTONDBLCLK: 34 | vk = VK_MBUTTON; 35 | break; 36 | } 37 | 38 | PyObject * pyarglist = Py_BuildValue("(iii)", pmousellhook->pt.x, pmousellhook->pt.y, vk ); 39 | PyObject * pyresult = PyObject_Call( pyfunc, pyarglist, NULL ); 40 | Py_DECREF(pyarglist); 41 | if(pyresult) 42 | { 43 | if( pyresult==Py_None ) 44 | { 45 | result = 0; 46 | } 47 | else 48 | { 49 | PyArg_Parse(pyresult,"i", &result ); 50 | } 51 | Py_DECREF(pyresult); 52 | } 53 | else 54 | { 55 | PyErr_Print(); 56 | result = 0; 57 | } 58 | 59 | return result; 60 | } 61 | 62 | static int OnMouseWheel(WPARAM wParam, MSLLHOOKSTRUCT * pmousellhook, PyObject * pyfunc) 63 | { 64 | int result; 65 | 66 | g.last_key_time = pmousellhook->time; 67 | 68 | PyObject * pyarglist = Py_BuildValue("(iif)", pmousellhook->pt.x, pmousellhook->pt.y, ((float)(short)HIWORD(pmousellhook->mouseData))/WHEEL_DELTA); 69 | PyObject * pyresult = PyObject_Call(pyfunc, pyarglist, NULL); 70 | Py_DECREF(pyarglist); 71 | if (pyresult) 72 | { 73 | if (pyresult == Py_None) 74 | { 75 | result = 0; 76 | } 77 | else 78 | { 79 | PyArg_Parse(pyresult, "i", &result); 80 | } 81 | Py_DECREF(pyresult); 82 | } 83 | else 84 | { 85 | PyErr_Print(); 86 | result = 0; 87 | } 88 | 89 | return result; 90 | } 91 | 92 | LRESULT CALLBACK MouseHookProc(int nCode, WPARAM wParam, LPARAM lParam) 93 | { 94 | PythonUtil::GIL_Ensure gil_ensure; 95 | 96 | if(nCode<0) 97 | { 98 | LRESULT result = CallNextHookEx(mouse_hook, nCode, wParam, lParam); 99 | return result; 100 | } 101 | 102 | MSLLHOOKSTRUCT * pmousellhook = (MSLLHOOKSTRUCT*)lParam; 103 | 104 | // タイムスタンプが逆転してしまった場合は、予期しないことが起きている 105 | if( g.last_key_time > pmousellhook->time ) 106 | { 107 | PythonUtil_Printf("Time stamp inversion happened.\n"); 108 | } 109 | 110 | // プログラムによって挿入されたキーイベントはスクリプトで処理しない 111 | if( pmousellhook->flags & LLMHF_INJECTED 112 | && pmousellhook->dwExtraInfo == (ULONG_PTR)g.module_handle ) 113 | { 114 | LRESULT result = CallNextHookEx(mouse_hook, nCode, wParam, lParam); 115 | return result; 116 | } 117 | 118 | switch(wParam) 119 | { 120 | case WM_LBUTTONDOWN: 121 | case WM_RBUTTONDOWN: 122 | case WM_MBUTTONDOWN: 123 | if( g.pyhook->mousedown ) 124 | { 125 | int result = OnMouseButton( wParam, pmousellhook, g.pyhook->mousedown ); 126 | if(result) 127 | { 128 | return result; 129 | } 130 | } 131 | break; 132 | 133 | case WM_LBUTTONUP: 134 | case WM_RBUTTONUP: 135 | case WM_MBUTTONUP: 136 | if( g.pyhook->mouseup ) 137 | { 138 | int result = OnMouseButton( wParam, pmousellhook, g.pyhook->mouseup ); 139 | if(result) 140 | { 141 | return result; 142 | } 143 | } 144 | break; 145 | 146 | case WM_LBUTTONDBLCLK: 147 | case WM_RBUTTONDBLCLK: 148 | case WM_MBUTTONDBLCLK: 149 | if( g.pyhook->mousedblclk ) 150 | { 151 | int result = OnMouseButton( wParam, pmousellhook, g.pyhook->mousedblclk ); 152 | if(result) 153 | { 154 | return result; 155 | } 156 | } 157 | break; 158 | 159 | case WM_MOUSEWHEEL: 160 | if (g.pyhook->mousewheel) 161 | { 162 | int result = OnMouseWheel(wParam, pmousellhook, g.pyhook->mousewheel); 163 | if (result) 164 | { 165 | return result; 166 | } 167 | } 168 | break; 169 | 170 | case WM_MOUSEHWHEEL: 171 | if (g.pyhook->mousehorizontalwheel) 172 | { 173 | int result = OnMouseWheel(wParam, pmousellhook, g.pyhook->mousehorizontalwheel); 174 | if (result) 175 | { 176 | return result; 177 | } 178 | } 179 | break; 180 | 181 | } 182 | 183 | LRESULT result = CallNextHookEx(mouse_hook, nCode, wParam, lParam); 184 | return result; 185 | } 186 | 187 | void HookStart_Mouse() 188 | { 189 | if(!mouse_hook) 190 | { 191 | PythonUtil_DebugPrintf("SetWindowsHookEx\n" ); 192 | mouse_hook = SetWindowsHookEx( WH_MOUSE_LL, MouseHookProc, g.module_handle, 0 ); 193 | } 194 | 195 | if( mouse_hook==NULL ) 196 | { 197 | PythonUtil_Printf("SetWindowsHookEx failed : %x\n", GetLastError() ); 198 | } 199 | } 200 | 201 | void HookEnd_Mouse() 202 | { 203 | if(mouse_hook) 204 | { 205 | if( ! UnhookWindowsHookEx(mouse_hook) ) 206 | { 207 | PythonUtil_Printf("UnhookWindowsHookEx(mouse) failed\n"); 208 | } 209 | 210 | mouse_hook=NULL; 211 | } 212 | } 213 | -------------------------------------------------------------------------------- /pyautocore/pyautocore.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | x64 7 | 8 | 9 | Release 10 | x64 11 | 12 | 13 | 14 | {2D8BB990-8905-4DCF-8811-3F97A27BED1A} 15 | pyautocore 16 | Win32Proj 17 | 10.0.18362.0 18 | 19 | 20 | 21 | DynamicLibrary 22 | Unicode 23 | true 24 | v140 25 | 26 | 27 | DynamicLibrary 28 | Unicode 29 | v140 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | <_ProjectFileVersion>10.0.40219.1 43 | true 44 | false 45 | .pyd 46 | .pyd 47 | 48 | 49 | ..\ 50 | 51 | 52 | ..\ 53 | 54 | 55 | 56 | Disabled 57 | c:\Python313\include;%(AdditionalIncludeDirectories) 58 | _DEBUG;_WINDOWS;_USRDLL;PYAUTOCORE_EXPORTS;%(PreprocessorDefinitions) 59 | EnableFastChecks 60 | MultiThreadedDebugDLL 61 | 62 | 63 | Level3 64 | ProgramDatabase 65 | 66 | 67 | ..\$(ProjectName).pyd 68 | c:\Python313\libs;%(AdditionalLibraryDirectories) 69 | true 70 | Windows 71 | imm32.lib;%(AdditionalDependencies) 72 | 73 | 74 | 75 | 76 | MaxSpeed 77 | true 78 | c:\Python313\include;%(AdditionalIncludeDirectories) 79 | NDEBUG;_WINDOWS;_USRDLL;PYAUTOCORE_EXPORTS;%(PreprocessorDefinitions) 80 | MultiThreadedDLL 81 | true 82 | 83 | 84 | Level3 85 | ProgramDatabase 86 | 87 | 88 | imm32.lib;%(AdditionalDependencies) 89 | ..\$(ProjectName).pyd 90 | c:\Python313\libs;%(AdditionalLibraryDirectories) 91 | true 92 | Windows 93 | true 94 | true 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | -------------------------------------------------------------------------------- /doc/index.txt: -------------------------------------------------------------------------------- 1 | ====================================================== 2 | [ pyauto ] 3 | ====================================================== 4 | 5 | :著作者: craftware 6 | :連絡先: craftware@gmail.com 7 | :開発環境: Python + VisualC++2010 8 | :種別: フリーウェア 9 | :動作環境: Windows XP/Vista/7/8 10 | :Webサイト: http://sites.google.com/site/craftware/ 11 | 12 | .. contents:: 13 | 14 | 15 | 16 | このソフトウェアについて 17 | ========================= 18 | 19 | pyautoは、Windowsの操作をカスタマイズ/自動化するための、Python拡張モジュールです。 20 | 21 | pyautoを使うことによって、以下のことが可能になります。 22 | 23 | - デスクトップのウインドウの状態の取得 24 | - キー入力やフォーカス移動をフック 25 | - 擬似的なマウス/キーボード入力 26 | 27 | pyautoはフリーソフトウェアです。ソースコードが公開されています。 28 | 29 | 30 | 動作環境 31 | ========= 32 | 33 | pyautoを利用するには以下の環境が必要です。 34 | 35 | - Windows 36 | - Python 3.4 37 | 38 | 連絡先 39 | ======= 40 | 41 | pyautoに関する質問や要望は、 42 | 43 | - http://sites.google.com/site/craftware/ 44 | - .. image:: image/mailaddress.png 45 | 46 | までお願いします。 47 | 48 | 49 | APIリファレンス 50 | ================ 51 | 52 | pyauto が提供しているのクラスや関数の詳細については、 53 | APIリファレンス_ を参照してください。 54 | 55 | .. _APIリファレンス: reference/index.html 56 | 57 | 58 | 59 | 更新履歴 60 | ========= 61 | 62 | **?.??** 63 | 64 | - MouseHorizontalWheel クラスを追加 65 | 66 | **1.28** 67 | 68 | - Window.maximize(), Window.minimize(), Window.restore() に、SetWindowPlacement() ではなく、WM_SYSCOMMAND を使うようにした。 69 | これにより、最大化したまま最小化したウインドウを restore() するときに、通常サイズに戻ることなく、最大化状態で復帰するようにした。 70 | 71 | - ビルド方法の整理。C++部分は Visual C++ 2008 (Express)を使うようにした。 72 | 73 | - ドキュメント生成に使用している Doxygen のバージョンアップ 74 | 75 | **1.27** 76 | 77 | - KEYEVENTF_UNICODE | KEYEVENTF_KEYUP の送り漏れ修正 78 | 79 | **1.26** 80 | 81 | - python27を使うようにした。 82 | 83 | - Window.getImeStatus / Window.setImeStatus を追加 84 | 85 | - クリップボードビューアのチェインの後続に WM_DRAWCLIPBOARD を通知していなかったのを修正。 86 | 87 | **1.25** 88 | 89 | - setForeground の force 引数を使った後、インプットとスレッドの関連付けを元に戻してなかったのを修正 90 | 91 | **1.24** 92 | 93 | - focus のフックは、64bit のアプリで動作しないので廃止。 94 | (代わりにgetFocus()を使用することができる。) 95 | 96 | **1.23** 97 | 98 | - クリップボードのフックにNoneを渡したときに、クリップボードビューアを解除し忘れていたのを修正 99 | 100 | **1.22** 101 | 102 | - Input.getKeyState(), Input.getAsyncKeyState() を追加 103 | 104 | - setDebug() を追加 105 | 106 | - Window.getClientRect(), Window.clientToScreen(), Window.getCaret() を追加 107 | 108 | - Window.getFocus() で AttachThreadInput を使わず GetGUIThreadInfo を使うようにした。AttachThreadInputには副作用があるため。 109 | 110 | - Window.getProcessName と Window.getProcessPath で、ウィンドウを作成したプロセスが見つからなかったときは、エラーにするのではなくて、空文字列を返すようにした。 111 | 112 | - ドキュメントの形式を Rst と Doxygen に変更 113 | 114 | **1.21** 115 | 116 | - キーフックはDLLの中で受け取る必要がなかったので、pyautocore モジュールの中で受け取るようにした。 117 | 118 | - 擬似入力イベントの dwExtraInfo と time に、適切に情報を入れる。 119 | 120 | - printf の代わりに python の sys.stdout を使ってメッセージを出力する。 121 | 122 | **1.20** 123 | 124 | - Window.setActive を追加 125 | 126 | **1.19** 127 | 128 | - Hook.clipboard を追加。クリップボードの変更通知を受け取るためのフック関数。 129 | 130 | - python26を使うようにした。 131 | 132 | **1.18** 133 | 134 | - Window.getFileName を Window.getProcessPath と改名 135 | 136 | - Window.getProcessName を追加。Window.getProcessPath は 64bit で動作するプロセスには機能しないので、代わりにこちらを使う必要がある。 137 | 138 | - Window.getFocus を追加。 139 | 140 | - Input.getKeyboardState, Input.setKeyboardState を追加 141 | 142 | **1.17** 143 | 144 | - Char() に 長さ1の文字を与えられるようにした。 145 | 146 | - 仮想キーコードで抜けていた分を追加した。 147 | 148 | - Hook.destroy() を追加。 149 | 150 | - Window.getFileName がメモリ不足エラーを返すことがあるので、調査のために詳細なメッセージを出すようにする。 151 | 152 | - Window.getFileName がメモリ不足エラーを修正するために、秘密のビット TH32CS_SNAPNOHEAPS を追加。 153 | 154 | - Input の __repr__ を定義した。 155 | 156 | **1.16** 157 | 158 | - Window.getLastActivePopup() を追加 159 | 160 | **1.15** 161 | 162 | - Window.getMonitorInfo() のメモリリークを修正 163 | 164 | **1.14** 165 | 166 | - Window.getMonitorInfo() を追加 167 | 168 | **1.13** 169 | 170 | - Inputクラスで拡張キー(右シフトなど)の扱いが正しくなかったのを修正 171 | 172 | - keymapサンプルを更新 173 | 174 | **1.12** 175 | 176 | - messageLoopのなかのメッセージ待ちの時間は、ほかのPythonスレッドの動作を許す 177 | 178 | **1.11** 179 | 180 | - Win32API のエラーは OSError ではなく WindowsError を使う 181 | 182 | - Window.setForeground() に、force 引数を追加 183 | 184 | - Inputクラスのマウスクリック系でマウス移動が無効になっていたのを修正 185 | 186 | - フック終了後に、プロセス間共有のprintfのバッファを吐き出す 187 | 188 | **1.10** 189 | 190 | - Key/KeyDown/KeyUpの引数に1文字の文字列を与えられた場合は、自動的に仮想キーコードに変換するようにした。これに伴って1.09 でkeymapサンプルが動かなかった問題が修正された。 191 | 192 | **1.09** 193 | 194 | - SendMessageTimeout が 1400エラーになったときは、ウインドウハンドルを再取得する 195 | 196 | - keymapサンプルで、モディファイアキーが押しっぱなしになるのを修正 197 | 198 | - notepadをemacs風にするサンプルを拡充 199 | 200 | **1.08** 201 | 202 | - keymapサンプルを追加。フックを使用して、キー操作を各ウインドウ毎にカスタマイズするサンプル。 203 | 204 | **1.07** 205 | 206 | - window_enumサンプルを追加 207 | 208 | - Window.getFileName() を追加 209 | 210 | - Window.getHWND() / Window.fromHWND() を追加 211 | 212 | **1.06** 213 | 214 | - MouseMiddleDown / MouseMiddleUp / MouseMiddleClick / MouseWheel クラスを追加 215 | 216 | - Input.getCursorPos() スタティックメソッドを追加 217 | 218 | **1.05** 219 | 220 | - Pythonのバージョンを2.5に 221 | 222 | - HookクラスおよびmessageLoop()を追加 223 | 224 | **1.04** 225 | 226 | - Inputクラスの派生クラスとしてCharクラスを追加 227 | 228 | **1.03** 229 | 230 | - Image.find() で、横幅または高さが同じ画像の検索に常に失敗していた不具合の修正 231 | 232 | **1.02** 233 | 234 | - pyauto_const.pyに、WM_* と SC_* をいくつか追加 235 | - shellExecuteの引数swmodeには整数ではなく文字列を受け取るようにした 236 | - window_messageサンプルを追加 237 | - shellexecuteサンプルを追加 238 | 239 | **1.01** 240 | 241 | - Window.getClientRectを廃止 242 | - Window.setRectを追加 243 | - Window.minimizeを追加 244 | - Window.maximizeを追加 245 | - Window.restoreを追加 246 | - Window.setForegroundで、スレッドのインプット状態を切り替えながらフォアグラウンド化をするようにした。 247 | 248 | **1.00** 249 | 250 | - 最初の公開 251 | -------------------------------------------------------------------------------- /sample/keymap/keymap_hook.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf_8 -*- 2 | 3 | import re 4 | import pyauto 5 | 6 | MODKEY_ALT = 0x00000001 7 | MODKEY_CTRL = 0x00000002 8 | MODKEY_SHIFT = 0x00000004 9 | MODKEY_WIN = 0x00000008 10 | MODKEY_USER0 = 0x00000010 11 | MODKEY_USER1 = 0x00000020 12 | MODKEY_USER2 = 0x00000040 13 | MODKEY_USER3 = 0x00000080 14 | 15 | MODKEY_ALT_L = MODKEY_ALT | 0x00000100 16 | MODKEY_CTRL_L = MODKEY_CTRL | 0x00000200 17 | MODKEY_SHIFT_L = MODKEY_SHIFT | 0x00000400 18 | MODKEY_WIN_L = MODKEY_WIN | 0x00000800 19 | MODKEY_USER0_L = MODKEY_USER0 | 0x00001000 20 | MODKEY_USER1_L = MODKEY_USER1 | 0x00002000 21 | MODKEY_USER2_L = MODKEY_USER2 | 0x00004000 22 | MODKEY_USER3_L = MODKEY_USER3 | 0x00008000 23 | 24 | MODKEY_ALT_R = MODKEY_ALT | 0x00010000 25 | MODKEY_CTRL_R = MODKEY_CTRL | 0x00020000 26 | MODKEY_SHIFT_R = MODKEY_SHIFT | 0x00040000 27 | MODKEY_WIN_R = MODKEY_WIN | 0x00080000 28 | MODKEY_USER0_R = MODKEY_USER0 | 0x00100000 29 | MODKEY_USER1_R = MODKEY_USER1 | 0x00200000 30 | MODKEY_USER2_R = MODKEY_USER2 | 0x00400000 31 | MODKEY_USER3_R = MODKEY_USER3 | 0x00800000 32 | 33 | 34 | _keymap_list = [] 35 | _current_keymap = None 36 | _modifier = 0 37 | _vk_mod_map = {} 38 | 39 | 40 | def checkModifier( mod1, mod2 ): 41 | _mod1 = mod1 & 0xff 42 | _mod2 = mod2 & 0xff 43 | _mod1_L = (mod1 & 0xff00) >> 8 44 | _mod2_L = (mod2 & 0xff00) >> 8 45 | _mod1_R = (mod1 & 0xff0000) >> 16 46 | _mod2_R = (mod2 & 0xff0000) >> 16 47 | if _mod1 != _mod2 : return False 48 | if _mod1_L & _mod2_R : return False 49 | if _mod1_R & _mod2_L : return False 50 | return True 51 | 52 | 53 | def createKeySequence_ModifierDown(mod): 54 | seq = [] 55 | for vk_mod in _vk_mod_map.items(): 56 | if checkModifier( vk_mod[1], mod ): 57 | seq.append( pyauto.KeyDown(vk_mod[0]) ) 58 | return seq 59 | 60 | 61 | def createKeySequence_ModifierUp(mod): 62 | seq = [] 63 | for vk_mod in _vk_mod_map.items(): 64 | if checkModifier( vk_mod[1], mod ): 65 | seq.append( pyauto.KeyUp(vk_mod[0]) ) 66 | return seq 67 | 68 | 69 | class KeyStroke: 70 | 71 | def __init__(self,vk,mod=0,prefix=None): 72 | if type(vk)==str and len(vk)==1 : vk=ord(vk) 73 | self.vk = vk 74 | self.mod = mod 75 | self.prefix = prefix 76 | 77 | def __hash__(self): 78 | return self.vk 79 | 80 | def __eq__(self,other): 81 | if self.vk!=other.vk : return False 82 | if self.prefix!=other.prefix : return False 83 | if not checkModifier( self.mod, other.mod ) : return False 84 | return True 85 | 86 | 87 | K = KeyStroke 88 | 89 | 90 | class Keymap: 91 | 92 | def __init__(self,hwnd): 93 | #print "Keymap.__init__" 94 | self.keydown_table = {} 95 | self.keyup_table = {} 96 | self.prefix = None 97 | 98 | def onKeyDown( self, vk, mod ): 99 | key = KeyStroke(vk,mod,self.prefix) 100 | if key in self.keydown_table : 101 | handler = self.keydown_table[key] 102 | if type(handler)==list or type(handler)==tuple: 103 | key_seq = createKeySequence_ModifierUp(_modifier) + handler + createKeySequence_ModifierDown(_modifier) 104 | pyauto.Input.send(key_seq) 105 | elif callable(handler): 106 | handler() 107 | else: 108 | raise TypeError; 109 | return True 110 | return False 111 | 112 | def onKeyUp( self, vk, mod ): 113 | key = KeyStroke(vk,mod,self.prefix) 114 | if key in self.keyup_table : 115 | handler = self.keyup_table[key] 116 | if type(handler)==list or type(handler)==tuple: 117 | key_seq = createKeySequence_ModifierUp(_modifier) + handler + createKeySequence_ModifierDown(_modifier) 118 | pyauto.Input.send(key_seq) 119 | elif callable(handler): 120 | handler() 121 | else: 122 | raise TypeError; 123 | return True 124 | return False 125 | 126 | def registerKeyDownHandler( self, keystroke, handler ): 127 | self.keydown_table[ keystroke ] = handler 128 | 129 | def registerKeyUpHandler( self, keystroke, handler ): 130 | self.keyup_table[ keystroke ] = handler 131 | 132 | def setPrefix(self,prefix): 133 | self.prefix = prefix 134 | 135 | def resetPrefix(self): 136 | self.prefix = None 137 | 138 | 139 | def defineModifier( vk, mod ): 140 | _vk_mod_map[vk] = mod 141 | 142 | 143 | def registorKeymap( condition, constructor ): 144 | 145 | _condition = [ None, None, None ] 146 | 147 | if condition[0]!=None : _condition[0] = re.compile( condition[0] ) 148 | if condition[1]!=None : _condition[1] = re.compile( condition[1] ) 149 | if condition[2]!=None : _condition[2] = re.compile( condition[2] ) 150 | 151 | _keymap_list.insert( 0, ( tuple(_condition), constructor ) ) 152 | 153 | 154 | def quitKeymap(): 155 | global _hook 156 | #print "quitKeymap" 157 | del _hook 158 | 159 | 160 | def _onKeyDown( vk, scan ): 161 | global _vk_mod_map 162 | global _modifier 163 | global _current_keymap 164 | 165 | try: 166 | #print "onKeyDown : ", vk 167 | 168 | if vk in _vk_mod_map : _modifier |= _vk_mod_map[vk] 169 | 170 | if _current_keymap: 171 | return _current_keymap.onKeyDown(vk,_modifier) 172 | else: 173 | return False 174 | except Exception as e: 175 | print( e ) 176 | quitKeymap() 177 | 178 | 179 | def _onKeyUp( vk, scan ): 180 | global _vk_mod_map 181 | global _modifier 182 | global _current_keymap 183 | 184 | try: 185 | #print "onKeyUp : ", vk 186 | 187 | if vk in _vk_mod_map : _modifier &= ~_vk_mod_map[vk] 188 | 189 | if _current_keymap: 190 | return _current_keymap.onKeyUp(vk,_modifier) 191 | else: 192 | return False 193 | except Exception as e: 194 | print( e ) 195 | quitKeymap() 196 | 197 | 198 | _hook = pyauto.Hook() 199 | 200 | _hook.keydown = _onKeyDown 201 | _hook.keyup = _onKeyUp 202 | 203 | defineModifier( pyauto.VK_LSHIFT, MODKEY_SHIFT_L ) 204 | defineModifier( pyauto.VK_RSHIFT, MODKEY_SHIFT_R ) 205 | defineModifier( pyauto.VK_LCONTROL, MODKEY_CTRL_L ) 206 | defineModifier( pyauto.VK_RCONTROL, MODKEY_CTRL_R ) 207 | defineModifier( pyauto.VK_LMENU, MODKEY_ALT_L ) 208 | defineModifier( pyauto.VK_RMENU, MODKEY_ALT_R ) 209 | defineModifier( pyauto.VK_LWIN, MODKEY_WIN_L ) 210 | defineModifier( pyauto.VK_RWIN, MODKEY_WIN_R ) 211 | -------------------------------------------------------------------------------- /pyauto_const.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf_8 -*- 2 | 3 | #--- window message ----------------------------- 4 | WM_COMMAND = 0x0111 5 | WM_SYSCOMMAND = 0x0112 6 | 7 | #--- system command ----------------------------- 8 | SC_SIZE = 0xF000 9 | SC_MOVE = 0xF010 10 | SC_MINIMIZE = 0xF020 11 | SC_MAXIMIZE = 0xF030 12 | SC_NEXTWINDOW = 0xF040 13 | SC_PREVWINDOW = 0xF050 14 | SC_CLOSE = 0xF060 15 | SC_VSCROLL = 0xF070 16 | SC_HSCROLL = 0xF080 17 | SC_MOUSEMENU = 0xF090 18 | SC_KEYMENU = 0xF100 19 | SC_RESTORE = 0xF120 20 | SC_TASKLIST = 0xF130 21 | SC_SCREENSAVE = 0xF140 22 | SC_HOTKEY = 0xF150 23 | SC_DEFAULT = 0xF160 24 | SC_MONITORPOWER = 0xF170 25 | SC_CONTEXTHELP = 0xF180 26 | 27 | #--- virtual keycode ---------------------------- 28 | VK_LBUTTON = 0x01 29 | VK_RBUTTON = 0x02 30 | VK_CANCEL = 0x03 31 | VK_MBUTTON = 0x04 32 | VK_BACK = 0x08 33 | VK_TAB = 0x09 34 | VK_CLEAR = 0x0C 35 | VK_RETURN = 0x0D 36 | VK_SHIFT = 0x10 37 | VK_CONTROL = 0x11 38 | VK_MENU = 0x12 39 | VK_PAUSE = 0x13 40 | VK_CAPITAL = 0x14 41 | VK_KANA = 0x15 42 | VK_HANGUL = 0x15 43 | VK_JUNJA = 0x17 44 | VK_FINAL = 0x18 45 | VK_HANJA = 0x19 46 | VK_KANJI = 0x19 47 | VK_ESCAPE = 0x1B 48 | VK_CONVERT = 0x1C 49 | VK_NONCONVERT = 0x1D 50 | VK_ACCEPT = 0x1E 51 | VK_MODECHANGE = 0x1F 52 | VK_SPACE = 0x20 53 | VK_PRIOR = 0x21 54 | VK_NEXT = 0x22 55 | VK_END = 0x23 56 | VK_HOME = 0x24 57 | VK_LEFT = 0x25 58 | VK_UP = 0x26 59 | VK_RIGHT = 0x27 60 | VK_DOWN = 0x28 61 | VK_SELECT = 0x29 62 | VK_PRINT = 0x2A 63 | VK_EXECUTE = 0x2B 64 | VK_SNAPSHOT = 0x2C 65 | VK_INSERT = 0x2D 66 | VK_DELETE = 0x2E 67 | VK_HELP = 0x2F 68 | VK_0 = 0x30 69 | VK_1 = 0x31 70 | VK_2 = 0x32 71 | VK_3 = 0x33 72 | VK_4 = 0x34 73 | VK_5 = 0x35 74 | VK_6 = 0x36 75 | VK_7 = 0x37 76 | VK_8 = 0x38 77 | VK_9 = 0x39 78 | VK_A = 0x41 79 | VK_B = 0x42 80 | VK_C = 0x43 81 | VK_D = 0x44 82 | VK_E = 0x45 83 | VK_F = 0x46 84 | VK_G = 0x47 85 | VK_H = 0x48 86 | VK_I = 0x49 87 | VK_J = 0x4A 88 | VK_K = 0x4B 89 | VK_L = 0x4C 90 | VK_M = 0x4D 91 | VK_N = 0x4E 92 | VK_O = 0x4F 93 | VK_P = 0x50 94 | VK_Q = 0x51 95 | VK_R = 0x52 96 | VK_S = 0x53 97 | VK_T = 0x54 98 | VK_U = 0x55 99 | VK_V = 0x56 100 | VK_W = 0x57 101 | VK_X = 0x58 102 | VK_Y = 0x59 103 | VK_Z = 0x5A 104 | VK_LWIN = 0x5B 105 | VK_RWIN = 0x5C 106 | VK_APPS = 0x5D 107 | VK_NUMPAD0 = 0x60 108 | VK_NUMPAD1 = 0x61 109 | VK_NUMPAD2 = 0x62 110 | VK_NUMPAD3 = 0x63 111 | VK_NUMPAD4 = 0x64 112 | VK_NUMPAD5 = 0x65 113 | VK_NUMPAD6 = 0x66 114 | VK_NUMPAD7 = 0x67 115 | VK_NUMPAD8 = 0x68 116 | VK_NUMPAD9 = 0x69 117 | VK_MULTIPLY = 0x6A 118 | VK_ADD = 0x6B 119 | VK_SEPARATOR = 0x6C 120 | VK_SUBTRACT = 0x6D 121 | VK_DECIMAL = 0x6E 122 | VK_DIVIDE = 0x6F 123 | VK_F1 = 0x70 124 | VK_F2 = 0x71 125 | VK_F3 = 0x72 126 | VK_F4 = 0x73 127 | VK_F5 = 0x74 128 | VK_F6 = 0x75 129 | VK_F7 = 0x76 130 | VK_F8 = 0x77 131 | VK_F9 = 0x78 132 | VK_F10 = 0x79 133 | VK_F11 = 0x7A 134 | VK_F12 = 0x7B 135 | VK_F13 = 0x7C 136 | VK_F14 = 0x7D 137 | VK_F15 = 0x7E 138 | VK_F16 = 0x7F 139 | VK_F17 = 0x80 140 | VK_F18 = 0x81 141 | VK_F19 = 0x82 142 | VK_F20 = 0x83 143 | VK_F21 = 0x84 144 | VK_F22 = 0x85 145 | VK_F23 = 0x86 146 | VK_F24 = 0x87 147 | VK_NUMLOCK = 0x90 148 | VK_SCROLL = 0x91 149 | VK_LSHIFT = 0xA0 150 | VK_RSHIFT = 0xA1 151 | VK_LCONTROL = 0xA2 152 | VK_RCONTROL = 0xA3 153 | VK_LMENU = 0xA4 154 | VK_RMENU = 0xA5 155 | VK_BROWSER_BACK = 0xA6 156 | VK_BROWSER_FORWARD = 0xA7 157 | VK_BROWSER_REFRESH = 0xA8 158 | VK_BROWSER_STOP = 0xA9 159 | VK_BROWSER_SEARCH = 0xAA 160 | VK_BROWSER_FAVORITES = 0xAB 161 | VK_BROWSER_HOME = 0xAC 162 | VK_VOLUME_MUTE = 0xAD 163 | VK_VOLUME_DOWN = 0xAE 164 | VK_VOLUME_UP = 0xAF 165 | VK_MEDIA_NEXT_TRACK = 0xB0 166 | VK_MEDIA_PREV_TRACK = 0xB1 167 | VK_MEDIA_STOP = 0xB2 168 | VK_MEDIA_PLAY_PAUSE = 0xB3 169 | VK_LAUNCH_MAIL = 0xB4 170 | VK_LAUNCH_MEDIA_SELECT = 0xB5 171 | VK_LAUNCH_APP1 = 0xB6 172 | VK_LAUNCH_APP2 = 0xB7 173 | VK_OEM_1 = 0xBA 174 | VK_OEM_PLUS = 0xBB 175 | VK_OEM_COMMA = 0xBC 176 | VK_OEM_MINUS = 0xBD 177 | VK_OEM_PERIOD = 0xBE 178 | VK_OEM_2 = 0xBF 179 | VK_OEM_3 = 0xC0 180 | VK_OEM_4 = 0xDB 181 | VK_OEM_5 = 0xDC 182 | VK_OEM_6 = 0xDD 183 | VK_OEM_7 = 0xDE 184 | VK_OEM_8 = 0xDF 185 | VK_OEM_102 = 0xE2 186 | VK_PROCESSKEY = 0xE5 187 | VK_PACKET = 0xE7 188 | VK_ATTN = 0xF6 189 | VK_CRSEL = 0xF7 190 | VK_EXSEL = 0xF8 191 | VK_EREOF = 0xF9 192 | VK_PLAY = 0xFA 193 | VK_ZOOM = 0xFB 194 | VK_NONAME = 0xFC 195 | VK_PA1 = 0xFD 196 | VK_OEM_CLEAR = 0xFE 197 | 198 | -------------------------------------------------------------------------------- /tool/rst2html_pygments.css: -------------------------------------------------------------------------------- 1 | /* 2 | :Author: David Goodger (goodger@python.org) 3 | :Id: $Id: html4css1.css 5951 2009-05-18 18:03:10Z milde $ 4 | :Copyright: This stylesheet has been placed in the public domain. 5 | 6 | Default cascading style sheet for the HTML output of Docutils. 7 | 8 | See http://docutils.sf.net/docs/howto/html-stylesheets.html for how to 9 | customize this style sheet. 10 | */ 11 | 12 | /* used to remove borders from tables and images */ 13 | .borderless, table.borderless td, table.borderless th { 14 | border: 0 } 15 | 16 | table.borderless td, table.borderless th { 17 | /* Override padding for "table.docutils td" with "! important". 18 | The right padding separates the table cells. */ 19 | padding: 0 0.5em 0 0 ! important } 20 | 21 | .first { 22 | /* Override more specific margin styles with "! important". */ 23 | margin-top: 0 ! important } 24 | 25 | .last, .with-subtitle { 26 | margin-bottom: 0 ! important } 27 | 28 | .hidden { 29 | display: none } 30 | 31 | a.toc-backref { 32 | text-decoration: none ; 33 | color: black } 34 | 35 | blockquote.epigraph { 36 | margin: 2em 5em ; } 37 | 38 | dl.docutils dd { 39 | margin-bottom: 0.5em } 40 | 41 | /* Uncomment (and remove this text!) to get bold-faced definition list terms 42 | dl.docutils dt { 43 | font-weight: bold } 44 | */ 45 | 46 | div.abstract { 47 | margin: 2em 5em } 48 | 49 | div.abstract p.topic-title { 50 | font-weight: bold ; 51 | text-align: center } 52 | 53 | div.admonition, div.attention, div.caution, div.danger, div.error, 54 | div.hint, div.important, div.note, div.tip, div.warning { 55 | margin: 2em ; 56 | border: medium outset ; 57 | padding: 1em } 58 | 59 | div.admonition p.admonition-title, div.hint p.admonition-title, 60 | div.important p.admonition-title, div.note p.admonition-title, 61 | div.tip p.admonition-title { 62 | font-weight: bold ; 63 | font-family: sans-serif } 64 | 65 | div.attention p.admonition-title, div.caution p.admonition-title, 66 | div.danger p.admonition-title, div.error p.admonition-title, 67 | div.warning p.admonition-title { 68 | color: red ; 69 | font-weight: bold ; 70 | font-family: sans-serif } 71 | 72 | /* Uncomment (and remove this text!) to get reduced vertical space in 73 | compound paragraphs. 74 | div.compound .compound-first, div.compound .compound-middle { 75 | margin-bottom: 0.5em } 76 | 77 | div.compound .compound-last, div.compound .compound-middle { 78 | margin-top: 0.5em } 79 | */ 80 | 81 | div.dedication { 82 | margin: 2em 5em ; 83 | text-align: center ; 84 | font-style: italic } 85 | 86 | div.dedication p.topic-title { 87 | font-weight: bold ; 88 | font-style: normal } 89 | 90 | div.figure { 91 | margin-left: 2em ; 92 | margin-right: 2em } 93 | 94 | div.footer, div.header { 95 | clear: both; 96 | font-size: smaller } 97 | 98 | div.line-block { 99 | display: block ; 100 | margin-top: 1em ; 101 | margin-bottom: 1em } 102 | 103 | div.line-block div.line-block { 104 | margin-top: 0 ; 105 | margin-bottom: 0 ; 106 | margin-left: 1.5em } 107 | 108 | div.sidebar { 109 | margin: 0 0 0.5em 1em ; 110 | border: medium outset ; 111 | padding: 1em ; 112 | background-color: #ffffee ; 113 | width: 40% ; 114 | float: right ; 115 | clear: right } 116 | 117 | div.sidebar p.rubric { 118 | font-family: sans-serif ; 119 | font-size: medium } 120 | 121 | div.system-messages { 122 | margin: 5em } 123 | 124 | div.system-messages h1 { 125 | color: red } 126 | 127 | div.system-message { 128 | border: medium outset ; 129 | padding: 1em } 130 | 131 | div.system-message p.system-message-title { 132 | color: red ; 133 | font-weight: bold } 134 | 135 | div.topic { 136 | margin: 2em } 137 | 138 | h1.section-subtitle, h2.section-subtitle, h3.section-subtitle, 139 | h4.section-subtitle, h5.section-subtitle, h6.section-subtitle { 140 | margin-top: 0.4em } 141 | 142 | h1.title { 143 | text-align: center } 144 | 145 | h2.subtitle { 146 | text-align: center } 147 | 148 | hr.docutils { 149 | width: 75% } 150 | 151 | img.align-left, .figure.align-left{ 152 | clear: left ; 153 | float: left ; 154 | margin-right: 1em } 155 | 156 | img.align-right, .figure.align-right { 157 | clear: right ; 158 | float: right ; 159 | margin-left: 1em } 160 | 161 | .align-left { 162 | text-align: left } 163 | 164 | .align-center { 165 | clear: both ; 166 | text-align: center } 167 | 168 | .align-right { 169 | text-align: right } 170 | 171 | /* reset inner alignment in figures */ 172 | div.align-right { 173 | text-align: left } 174 | 175 | /* div.align-center * { */ 176 | /* text-align: left } */ 177 | 178 | ol.simple, ul.simple { 179 | margin-bottom: 1em } 180 | 181 | ol.arabic { 182 | list-style: decimal } 183 | 184 | ol.loweralpha { 185 | list-style: lower-alpha } 186 | 187 | ol.upperalpha { 188 | list-style: upper-alpha } 189 | 190 | ol.lowerroman { 191 | list-style: lower-roman } 192 | 193 | ol.upperroman { 194 | list-style: upper-roman } 195 | 196 | p.attribution { 197 | text-align: right ; 198 | margin-left: 50% } 199 | 200 | p.caption { 201 | font-style: italic } 202 | 203 | p.credits { 204 | font-style: italic ; 205 | font-size: smaller } 206 | 207 | p.label { 208 | white-space: nowrap } 209 | 210 | p.rubric { 211 | font-weight: bold ; 212 | font-size: larger ; 213 | color: maroon ; 214 | text-align: center } 215 | 216 | p.sidebar-title { 217 | font-family: sans-serif ; 218 | font-weight: bold ; 219 | font-size: larger } 220 | 221 | p.sidebar-subtitle { 222 | font-family: sans-serif ; 223 | font-weight: bold } 224 | 225 | p.topic-title { 226 | font-weight: bold } 227 | 228 | pre.address { 229 | margin-bottom: 0 ; 230 | margin-top: 0 ; 231 | font: inherit } 232 | 233 | pre.literal-block, pre.doctest-block { 234 | margin-left: 2em ; 235 | margin-right: 2em } 236 | 237 | span.classifier { 238 | font-family: sans-serif ; 239 | font-style: oblique } 240 | 241 | span.classifier-delimiter { 242 | font-family: sans-serif ; 243 | font-weight: bold } 244 | 245 | span.interpreted { 246 | font-family: sans-serif } 247 | 248 | span.option { 249 | white-space: nowrap } 250 | 251 | span.pre { 252 | white-space: pre } 253 | 254 | span.problematic { 255 | color: red } 256 | 257 | span.section-subtitle { 258 | /* font-size relative to parent (h1..h6 element) */ 259 | font-size: 80% } 260 | 261 | table.citation { 262 | border-left: solid 1px gray; 263 | margin-left: 1px } 264 | 265 | table.docinfo { 266 | margin: 2em 4em } 267 | 268 | table.docutils { 269 | margin-top: 0.5em ; 270 | margin-bottom: 0.5em } 271 | 272 | table.footnote { 273 | border-left: solid 1px black; 274 | margin-left: 1px } 275 | 276 | table.docutils td, table.docutils th, 277 | table.docinfo td, table.docinfo th { 278 | padding-left: 0.5em ; 279 | padding-right: 0.5em ; 280 | vertical-align: top } 281 | 282 | table.docutils th.field-name, table.docinfo th.docinfo-name { 283 | font-weight: bold ; 284 | text-align: left ; 285 | white-space: nowrap ; 286 | padding-left: 0 } 287 | 288 | h1 tt.docutils, h2 tt.docutils, h3 tt.docutils, 289 | h4 tt.docutils, h5 tt.docutils, h6 tt.docutils { 290 | font-size: 100% } 291 | 292 | ul.auto-toc { 293 | list-style-type: none } 294 | 295 | /* added by craftware */ 296 | 297 | div.highlight { 298 | margin-left: 4em; 299 | margin-right: 4em; 300 | background-color: #dddddd } 301 | 302 | .hll { background-color: #ffffcc } 303 | .c { color: #408080; font-style: italic } /* Comment */ 304 | .err { border: 1px solid #FF0000 } /* Error */ 305 | .k { color: #008000; font-weight: bold } /* Keyword */ 306 | .o { color: #666666 } /* Operator */ 307 | .cm { color: #408080; font-style: italic } /* Comment.Multiline */ 308 | .cp { color: #BC7A00 } /* Comment.Preproc */ 309 | .c1 { color: #408080; font-style: italic } /* Comment.Single */ 310 | .cs { color: #408080; font-style: italic } /* Comment.Special */ 311 | .gd { color: #A00000 } /* Generic.Deleted */ 312 | .ge { font-style: italic } /* Generic.Emph */ 313 | .gr { color: #FF0000 } /* Generic.Error */ 314 | .gh { color: #000080; font-weight: bold } /* Generic.Heading */ 315 | .gi { color: #00A000 } /* Generic.Inserted */ 316 | .go { color: #808080 } /* Generic.Output */ 317 | .gp { color: #000080; font-weight: bold } /* Generic.Prompt */ 318 | .gs { font-weight: bold } /* Generic.Strong */ 319 | .gu { color: #800080; font-weight: bold } /* Generic.Subheading */ 320 | .gt { color: #0040D0 } /* Generic.Traceback */ 321 | .kc { color: #008000; font-weight: bold } /* Keyword.Constant */ 322 | .kd { color: #008000; font-weight: bold } /* Keyword.Declaration */ 323 | .kn { color: #008000; font-weight: bold } /* Keyword.Namespace */ 324 | .kp { color: #008000 } /* Keyword.Pseudo */ 325 | .kr { color: #008000; font-weight: bold } /* Keyword.Reserved */ 326 | .kt { color: #B00040 } /* Keyword.Type */ 327 | .m { color: #666666 } /* Literal.Number */ 328 | .s { color: #BA2121 } /* Literal.String */ 329 | .na { color: #7D9029 } /* Name.Attribute */ 330 | .nb { color: #008000 } /* Name.Builtin */ 331 | .nc { color: #0000FF; font-weight: bold } /* Name.Class */ 332 | .no { color: #880000 } /* Name.Constant */ 333 | .nd { color: #AA22FF } /* Name.Decorator */ 334 | .ni { color: #999999; font-weight: bold } /* Name.Entity */ 335 | .ne { color: #D2413A; font-weight: bold } /* Name.Exception */ 336 | .nf { color: #0000FF } /* Name.Function */ 337 | .nl { color: #A0A000 } /* Name.Label */ 338 | .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */ 339 | .nt { color: #008000; font-weight: bold } /* Name.Tag */ 340 | .nv { color: #19177C } /* Name.Variable */ 341 | .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */ 342 | .w { color: #bbbbbb } /* Text.Whitespace */ 343 | .mf { color: #666666 } /* Literal.Number.Float */ 344 | .mh { color: #666666 } /* Literal.Number.Hex */ 345 | .mi { color: #666666 } /* Literal.Number.Integer */ 346 | .mo { color: #666666 } /* Literal.Number.Oct */ 347 | .sb { color: #BA2121 } /* Literal.String.Backtick */ 348 | .sc { color: #BA2121 } /* Literal.String.Char */ 349 | .sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */ 350 | .s2 { color: #BA2121 } /* Literal.String.Double */ 351 | .se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */ 352 | .sh { color: #BA2121 } /* Literal.String.Heredoc */ 353 | .si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */ 354 | .sx { color: #008000 } /* Literal.String.Other */ 355 | .sr { color: #BB6688 } /* Literal.String.Regex */ 356 | .s1 { color: #BA2121 } /* Literal.String.Single */ 357 | .ss { color: #19177C } /* Literal.String.Symbol */ 358 | .bp { color: #008000 } /* Name.Builtin.Pseudo */ 359 | .vc { color: #19177C } /* Name.Variable.Class */ 360 | .vg { color: #19177C } /* Name.Variable.Global */ 361 | .vi { color: #19177C } /* Name.Variable.Instance */ 362 | .il { color: #666666 } /* Literal.Number.Integer.Long */ 363 | 364 | -------------------------------------------------------------------------------- /sample/keymap/config.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf_8 -*- 2 | 3 | from pyauto import * 4 | from keymap import * 5 | 6 | # ------------- Modifier ------------------------------------------------- 7 | 8 | defineModifier( 235, MODKEY_USER0_L ) 9 | 10 | 11 | # ------------- Global --------------------------------------------------- 12 | 13 | class Keymap_Global( Keymap ): 14 | 15 | def __init__(self,wnd): 16 | Keymap.__init__(self,wnd) 17 | 18 | #print "Keymap_Global.__init__" 19 | 20 | def getTopLevelWindow( wnd ): 21 | parent = wnd.getParent() 22 | while parent != Window.getDesktop(): 23 | wnd = parent; 24 | parent = wnd.getParent() 25 | return wnd 26 | 27 | # アプリの最上位ウインドウを取得する 28 | self.wnd_top = getTopLevelWindow(wnd) 29 | 30 | # Ctrl-F12 : pyautoのmessageLoopを中断する 31 | self.registerKeyDownHandler( K( VK_F12, MODKEY_USER0 ), quitKeymap ) 32 | self.registerKeyDownHandler( K( VK_F5, MODKEY_USER0 ), loadConfigFile ) 33 | 34 | # USER0-↑↓←→ : 10pixel単位のウインドウの移動 35 | self.registerKeyDownHandler( K( VK_LEFT, MODKEY_USER0 ), self.WindowMoveLeft ) 36 | self.registerKeyDownHandler( K( VK_RIGHT, MODKEY_USER0 ), self.WindowMoveRight ) 37 | self.registerKeyDownHandler( K( VK_UP, MODKEY_USER0 ), self.WindowMoveUp ) 38 | self.registerKeyDownHandler( K( VK_DOWN, MODKEY_USER0 ), self.WindowMoveDown ) 39 | 40 | # USER0-Shift-↑↓←→ : 1pixel単位のウインドウの移動 41 | self.registerKeyDownHandler( K( VK_LEFT, MODKEY_USER0 | MODKEY_SHIFT ), self.WindowMoveLeft1dot ) 42 | self.registerKeyDownHandler( K( VK_RIGHT, MODKEY_USER0 | MODKEY_SHIFT ), self.WindowMoveRight1dot ) 43 | self.registerKeyDownHandler( K( VK_UP, MODKEY_USER0 | MODKEY_SHIFT ), self.WindowMoveUp1dot ) 44 | self.registerKeyDownHandler( K( VK_DOWN, MODKEY_USER0 | MODKEY_SHIFT ), self.WindowMoveDown1dot ) 45 | 46 | # USER0-Ctrl-↑↓←→ : 画面の端まで移動 47 | self.registerKeyDownHandler( K( VK_LEFT, MODKEY_CTRL | MODKEY_USER0 ), self.WindowMoveLeftEdge ) 48 | self.registerKeyDownHandler( K( VK_RIGHT, MODKEY_CTRL | MODKEY_USER0 ), self.WindowMoveRightEdge ) 49 | self.registerKeyDownHandler( K( VK_UP, MODKEY_CTRL | MODKEY_USER0 ), self.WindowMoveUpEdge ) 50 | self.registerKeyDownHandler( K( VK_DOWN, MODKEY_CTRL | MODKEY_USER0 ), self.WindowMoveDownEdge ) 51 | 52 | def WindowMoveLeft( self ): 53 | rect = list(self.wnd_top.getRect()) 54 | rect[0] -= 10 55 | rect[2] -= 10 56 | self.wnd_top.setRect(rect) 57 | 58 | def WindowMoveRight( self ): 59 | rect = list(self.wnd_top.getRect()) 60 | rect[0] += 10 61 | rect[2] += 10 62 | self.wnd_top.setRect(rect) 63 | 64 | def WindowMoveUp( self ): 65 | rect = list(self.wnd_top.getRect()) 66 | rect[1] -= 10 67 | rect[3] -= 10 68 | self.wnd_top.setRect(rect) 69 | 70 | def WindowMoveDown( self ): 71 | rect = list(self.wnd_top.getRect()) 72 | rect[1] += 10 73 | rect[3] += 10 74 | self.wnd_top.setRect(rect) 75 | 76 | def WindowMoveLeft1dot( self ): 77 | rect = list(self.wnd_top.getRect()) 78 | rect[0] -= 1 79 | rect[2] -= 1 80 | self.wnd_top.setRect(rect) 81 | 82 | def WindowMoveRight1dot( self ): 83 | rect = list(self.wnd_top.getRect()) 84 | rect[0] += 1 85 | rect[2] += 1 86 | self.wnd_top.setRect(rect) 87 | 88 | def WindowMoveUp1dot( self ): 89 | rect = list(self.wnd_top.getRect()) 90 | rect[1] -= 1 91 | rect[3] -= 1 92 | self.wnd_top.setRect(rect) 93 | 94 | def WindowMoveDown1dot( self ): 95 | rect = list(self.wnd_top.getRect()) 96 | rect[1] += 1 97 | rect[3] += 1 98 | self.wnd_top.setRect(rect) 99 | 100 | def getDesktopRect(self): 101 | return Window.getDesktop().getRect() 102 | 103 | def getWorkingArea(self): 104 | desktop_rect = Window.getDesktop().getRect() 105 | taskbar_rect = Window.find("Shell_TrayWnd",None).getRect() 106 | 107 | rect = list(desktop_rect) 108 | 109 | if taskbar_rect[0]>desktop_rect[0] and taskbar_rect[0]desktop_rect[1] and taskbar_rect[1]desktop_rect[0] and taskbar_rect[2]desktop_rect[1] and taskbar_rect[3] 2 | #include 3 | #include 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | #if defined(_DEBUG) 10 | #undef _DEBUG 11 | #include "python.h" 12 | #define _DEBUG 13 | #else 14 | #include "python.h" 15 | #endif 16 | 17 | #include "kbhook.h" 18 | #include "mousehook.h" 19 | #include "clipboard.h" 20 | #include "pythonutil.h" 21 | #include "pyautocore.h" 22 | 23 | using namespace std; 24 | 25 | // ------------ const ----------------------------------- 26 | #define MODULE_NAME "pyautocore" 27 | #define PYAUTO_WINDOW_NAME "pyauto" 28 | 29 | // ------------ globals ----------------------------------- 30 | 31 | namespace pyauto 32 | { 33 | Globals g; 34 | }; 35 | 36 | using namespace pyauto; 37 | 38 | // ------------ stringutil ----------------------------------- 39 | 40 | namespace pyauto 41 | { 42 | #ifdef _UNICODE 43 | typedef wstring _tString; 44 | #else 45 | typedef string _tString; 46 | #endif 47 | 48 | namespace stringutil 49 | { 50 | static wstring MultiByteToWideChar( const char * str, int len ) 51 | { 52 | int buf_size = len+2; 53 | WCHAR * buf = new WCHAR[ buf_size ]; 54 | int write_len = ::MultiByteToWideChar( 0, 0, str, len, buf, buf_size ); 55 | buf[write_len] = '\0'; 56 | 57 | wstring ret = buf; 58 | 59 | delete [] buf; 60 | 61 | return ret; 62 | } 63 | 64 | static string WideCharToMultiByte( const WCHAR * str, int len ) 65 | { 66 | int buf_size = len*2+2; 67 | char * buf = new char[ buf_size ]; 68 | int write_len = ::WideCharToMultiByte( 0, 0, str, len, buf, buf_size, NULL, NULL ); 69 | buf[write_len] = '\0'; 70 | 71 | string ret = buf; 72 | 73 | delete [] buf; 74 | 75 | return ret; 76 | } 77 | 78 | static bool PyStringTo_tString( PyObject * pystr, _tString * str ) 79 | { 80 | if( PyUnicode_Check(pystr) ) 81 | { 82 | #if _UNICODE 83 | 84 | Py_ssize_t len; 85 | const wchar_t* s = PyUnicode_AsWideCharString(pystr, &len); 86 | 87 | *str = s; 88 | #else 89 | *str = WideCharToMultiByte( (const wchar_t*)PyUnicode_AS_UNICODE(pystr), PyUnicode_GET_SIZE(pystr) ); 90 | #endif 91 | return true; 92 | } 93 | else 94 | { 95 | *str = _T(""); 96 | return false; 97 | } 98 | } 99 | 100 | 101 | }; 102 | }; 103 | 104 | // ------------ PyObject_Window ----------------------------------------- 105 | 106 | namespace pyauto 107 | { 108 | static list window_list; 109 | 110 | static PyObject * WindowObject_FromHWND( HWND hwnd ) 111 | { 112 | if(!hwnd) 113 | { 114 | Py_INCREF(Py_None); 115 | return Py_None; 116 | } 117 | 118 | list::iterator i; 119 | for( i=window_list.begin() ; i!=window_list.end() ; i++ ) 120 | { 121 | if( ((PyObject_Window*)(*i))->hwnd==hwnd ) 122 | { 123 | Py_INCREF(*i); 124 | return (*i); 125 | } 126 | } 127 | 128 | PyObject_Window * pywnd; 129 | pywnd = PyObject_New( PyObject_Window, &PyType_Window ); 130 | pywnd->hwnd = hwnd; 131 | 132 | window_list.push_back((PyObject*)pywnd); 133 | 134 | return (PyObject*)pywnd; 135 | } 136 | 137 | static void WindowObject_Remove( PyObject * obj ) 138 | { 139 | list::iterator i; 140 | for( i=window_list.begin() ; i!=window_list.end() ; i++ ) 141 | { 142 | if( (*i)==obj ) 143 | { 144 | window_list.erase(i); 145 | return; 146 | } 147 | } 148 | } 149 | }; 150 | 151 | static void Window_dealloc(PyObject* self) 152 | { 153 | WindowObject_Remove(self); 154 | self->ob_type->tp_free(self); 155 | } 156 | 157 | static PyObject * Window_getText(PyObject* self, PyObject* args) 158 | { 159 | if( ! PyArg_ParseTuple(args, "" ) ) 160 | return NULL; 161 | 162 | HWND hwnd = ((PyObject_Window*)self)->hwnd; 163 | if(!hwnd) 164 | { 165 | PyErr_SetString( PyExc_ValueError, "invalid window object." ); 166 | return NULL; 167 | } 168 | 169 | int len = ::GetWindowTextLength(hwnd); 170 | 171 | TCHAR * buf = new TCHAR[len+2]; 172 | ::GetWindowText( hwnd, buf, len+2 ); 173 | 174 | #ifdef _UNICODE 175 | PyObject * pyret = Py_BuildValue("u",buf); 176 | #else 177 | wstring wstr = stringutil::MultiByteToWideChar( buf, len ); 178 | PyObject * pyret = Py_BuildValue("u",wstr.c_str()); 179 | #endif 180 | 181 | delete [] buf; 182 | 183 | return pyret; 184 | } 185 | 186 | static PyObject * Window_getClassName(PyObject* self, PyObject* args) 187 | { 188 | if( ! PyArg_ParseTuple(args, "" ) ) 189 | return NULL; 190 | 191 | HWND hwnd = ((PyObject_Window*)self)->hwnd; 192 | if(!hwnd) 193 | { 194 | PyErr_SetString( PyExc_ValueError, "invalid window object." ); 195 | return NULL; 196 | } 197 | 198 | TCHAR buf[256]; 199 | ::GetClassName( hwnd, buf, sizeof(buf) ); 200 | 201 | #ifdef _UNICODE 202 | PyObject * pyret = Py_BuildValue("u",buf); 203 | #else 204 | wstring wstr = stringutil::MultiByteToWideChar( buf, lstrlen(buf) ); 205 | PyObject * pyret = Py_BuildValue("u",wstr.c_str()); 206 | #endif 207 | 208 | return pyret; 209 | } 210 | 211 | static bool _Window_getProcessInfoFromHWND( HWND hwnd, TCHAR * process_name, TCHAR * process_path ) 212 | { 213 | // ヒープ情報をスナップしない秘密のビット 214 | #define TH32CS_SNAPNOHEAPS (0x40000000) 215 | 216 | DWORD pid = 0; 217 | GetWindowThreadProcessId( hwnd, &pid ); 218 | 219 | bool ret = false; 220 | HANDLE process_snapshot = CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS | TH32CS_SNAPNOHEAPS, 0 ); 221 | if(process_snapshot!=INVALID_HANDLE_VALUE) 222 | { 223 | PROCESSENTRY32 process_entry; 224 | process_entry.dwSize = sizeof(PROCESSENTRY32); 225 | if(Process32First( process_snapshot, &process_entry )) 226 | { 227 | while(true) 228 | { 229 | if(process_entry.th32ProcessID == pid) 230 | { 231 | if(process_name) 232 | { 233 | lstrcpy( process_name, process_entry.szExeFile ); 234 | ret = true; 235 | } 236 | 237 | if(process_path) 238 | { 239 | HANDLE module_handle = CreateToolhelp32Snapshot( TH32CS_SNAPMODULE | TH32CS_SNAPNOHEAPS, process_entry.th32ProcessID ); 240 | if(module_handle==INVALID_HANDLE_VALUE) 241 | { 242 | PyErr_Format( PyExc_WindowsError, "CreateToolhelp32Snapshot failed : lineno=%d errno=%d", __LINE__, GetLastError() ); 243 | break; 244 | } 245 | 246 | MODULEENTRY32 module_entry; 247 | module_entry.dwSize = sizeof(MODULEENTRY32); 248 | if( Module32First( module_handle, &module_entry ) ) 249 | { 250 | lstrcpy( process_path, module_entry.szExePath ); 251 | ret = true; 252 | } 253 | else 254 | { 255 | PyErr_Format( PyExc_WindowsError, "Module32First failed : lineno=%d errno=%d", __LINE__, GetLastError() ); 256 | } 257 | 258 | CloseHandle(module_handle); 259 | } 260 | 261 | break; 262 | } 263 | 264 | if(!Process32Next( process_snapshot, &process_entry )) 265 | { 266 | if(GetLastError()==ERROR_NO_MORE_FILES) 267 | { 268 | if(process_name) 269 | { 270 | lstrcpy( process_name, L"" ); 271 | } 272 | if(process_path) 273 | { 274 | lstrcpy( process_path, L"" ); 275 | } 276 | ret = true; 277 | break; 278 | } 279 | 280 | PyErr_Format( PyExc_WindowsError, "Process32Next failed : lineno=%d errno=%d", __LINE__, GetLastError() ); 281 | break; 282 | } 283 | } 284 | } 285 | else 286 | { 287 | PyErr_Format( PyExc_WindowsError, "Process32First failed : lineno=%d errno=%d", __LINE__, GetLastError() ); 288 | } 289 | 290 | CloseHandle(process_snapshot); 291 | } 292 | else 293 | { 294 | PyErr_Format( PyExc_WindowsError, "CreateToolhelp32Snapshot failed : lineno=%d errno=%d", __LINE__, GetLastError() ); 295 | } 296 | 297 | return ret; 298 | } 299 | 300 | static PyObject * Window_getProcessName(PyObject* self, PyObject* args) 301 | { 302 | if( ! PyArg_ParseTuple(args, "" ) ) 303 | return NULL; 304 | 305 | HWND hwnd = ((PyObject_Window*)self)->hwnd; 306 | if(!hwnd) 307 | { 308 | PyErr_SetString( PyExc_ValueError, "invalid window object." ); 309 | return NULL; 310 | } 311 | 312 | TCHAR buf[MAX_PATH]; 313 | bool ret = _Window_getProcessInfoFromHWND( hwnd, buf, NULL ); 314 | if(!ret) 315 | { 316 | //PyErr_SetFromWindowsErr(0); // _Window_getProcessInfoFromHWND のなかでエラーをセットする 317 | 318 | return NULL; 319 | } 320 | 321 | #ifdef _UNICODE 322 | PyObject * pyret = Py_BuildValue("u",buf); 323 | #else 324 | wstring wstr = stringutil::MultiByteToWideChar( buf, lstrlen(buf) ); 325 | PyObject * pyret = Py_BuildValue("u",wstr.c_str()); 326 | #endif 327 | 328 | return pyret; 329 | } 330 | 331 | static PyObject * Window_getProcessPath(PyObject* self, PyObject* args) 332 | { 333 | if( ! PyArg_ParseTuple(args, "" ) ) 334 | return NULL; 335 | 336 | HWND hwnd = ((PyObject_Window*)self)->hwnd; 337 | if(!hwnd) 338 | { 339 | PyErr_SetString( PyExc_ValueError, "invalid window object." ); 340 | return NULL; 341 | } 342 | 343 | TCHAR buf[MAX_PATH]; 344 | bool ret = _Window_getProcessInfoFromHWND( hwnd, NULL, buf ); 345 | if(!ret) 346 | { 347 | //PyErr_SetFromWindowsErr(0); // _Window_getProcessInfoFromHWND のなかでエラーをセットする 348 | 349 | return NULL; 350 | } 351 | 352 | #ifdef _UNICODE 353 | PyObject * pyret = Py_BuildValue("u",buf); 354 | #else 355 | wstring wstr = stringutil::MultiByteToWideChar( buf, lstrlen(buf) ); 356 | PyObject * pyret = Py_BuildValue("u",wstr.c_str()); 357 | #endif 358 | 359 | return pyret; 360 | } 361 | 362 | static PyObject * Window_getHWND(PyObject* self, PyObject* args) 363 | { 364 | if( ! PyArg_ParseTuple(args, "" ) ) 365 | return NULL; 366 | 367 | HWND hwnd = ((PyObject_Window*)self)->hwnd; 368 | if(!hwnd) 369 | { 370 | PyErr_SetString( PyExc_ValueError, "invalid window object." ); 371 | return NULL; 372 | } 373 | 374 | PyObject * pyret = Py_BuildValue("i",hwnd); 375 | return pyret; 376 | } 377 | 378 | static PyObject * Window_getRect(PyObject* self, PyObject* args) 379 | { 380 | if( ! PyArg_ParseTuple(args, "" ) ) 381 | return NULL; 382 | 383 | HWND hwnd = ((PyObject_Window*)self)->hwnd; 384 | if(!hwnd) 385 | { 386 | PyErr_SetString( PyExc_ValueError, "invalid window object." ); 387 | return NULL; 388 | } 389 | 390 | RECT rect; 391 | ::GetWindowRect(hwnd,&rect); 392 | 393 | PyObject * pyret = Py_BuildValue( "(iiii)", rect.left, rect.top, rect.right, rect.bottom ); 394 | return pyret; 395 | } 396 | 397 | static PyObject * Window_setRect(PyObject* self, PyObject* args) 398 | { 399 | RECT rect; 400 | 401 | if( ! PyArg_ParseTuple(args, "(iiii)", &rect.left, &rect.top, &rect.right, &rect.bottom ) ) 402 | return NULL; 403 | 404 | HWND hwnd = ((PyObject_Window*)self)->hwnd; 405 | if(!hwnd) 406 | { 407 | PyErr_SetString( PyExc_ValueError, "invalid window object." ); 408 | return NULL; 409 | } 410 | 411 | if( ::MoveWindow( hwnd, rect.left, rect.top, rect.right-rect.left, rect.bottom-rect.top, true ) ) 412 | { 413 | Py_INCREF(Py_None); 414 | return Py_None; 415 | } 416 | else 417 | { 418 | PyErr_SetFromWindowsErr(0); 419 | return NULL; 420 | } 421 | } 422 | 423 | static PyObject * Window_getClientRect(PyObject* self, PyObject* args) 424 | { 425 | if( ! PyArg_ParseTuple(args, "" ) ) 426 | return NULL; 427 | 428 | HWND hwnd = ((PyObject_Window*)self)->hwnd; 429 | if(!hwnd) 430 | { 431 | PyErr_SetString( PyExc_ValueError, "invalid window object." ); 432 | return NULL; 433 | } 434 | 435 | RECT rect; 436 | ::GetClientRect(hwnd,&rect); 437 | 438 | PyObject * pyret = Py_BuildValue( "(iiii)", rect.left, rect.top, rect.right, rect.bottom ); 439 | return pyret; 440 | } 441 | 442 | static PyObject * Window_clientToScreen(PyObject* self, PyObject* args) 443 | { 444 | int x; 445 | int y; 446 | 447 | if( ! PyArg_ParseTuple(args, "ii", &x, &y ) ) 448 | return NULL; 449 | 450 | HWND hwnd = ((PyObject_Window*)self)->hwnd; 451 | if(!hwnd) 452 | { 453 | PyErr_SetString( PyExc_ValueError, "invalid window object." ); 454 | return NULL; 455 | } 456 | 457 | POINT point; 458 | point.x = x; 459 | point.y = y; 460 | 461 | ClientToScreen( hwnd, &point ); 462 | 463 | PyObject * pyret = Py_BuildValue( "(ii)", point.x, point.y ); 464 | return pyret; 465 | } 466 | 467 | static PyObject * Window_getFirstChild(PyObject* self, PyObject* args) 468 | { 469 | if( ! PyArg_ParseTuple(args, "" ) ) 470 | return NULL; 471 | 472 | HWND hwnd = ((PyObject_Window*)self)->hwnd; 473 | if(!hwnd) 474 | { 475 | PyErr_SetString( PyExc_ValueError, "invalid window object." ); 476 | return NULL; 477 | } 478 | 479 | hwnd = ::GetWindow( hwnd, GW_CHILD ); 480 | return WindowObject_FromHWND(hwnd); 481 | } 482 | 483 | static PyObject * Window_getLastChild(PyObject* self, PyObject* args) 484 | { 485 | if( ! PyArg_ParseTuple(args, "" ) ) 486 | return NULL; 487 | 488 | HWND hwnd = ((PyObject_Window*)self)->hwnd; 489 | if(!hwnd) 490 | { 491 | PyErr_SetString( PyExc_ValueError, "invalid window object." ); 492 | return NULL; 493 | } 494 | 495 | hwnd = ::GetWindow( hwnd, GW_CHILD ); 496 | hwnd = ::GetWindow( hwnd, GW_HWNDLAST ); 497 | return WindowObject_FromHWND(hwnd); 498 | } 499 | 500 | static PyObject * Window_getPrevious(PyObject* self, PyObject* args) 501 | { 502 | if( ! PyArg_ParseTuple(args, "" ) ) 503 | return NULL; 504 | 505 | HWND hwnd = ((PyObject_Window*)self)->hwnd; 506 | if(!hwnd) 507 | { 508 | PyErr_SetString( PyExc_ValueError, "invalid window object." ); 509 | return NULL; 510 | } 511 | 512 | hwnd = ::GetWindow( hwnd, GW_HWNDPREV ); 513 | return WindowObject_FromHWND(hwnd); 514 | } 515 | 516 | static PyObject * Window_getNext(PyObject* self, PyObject* args) 517 | { 518 | if( ! PyArg_ParseTuple(args, "" ) ) 519 | return NULL; 520 | 521 | HWND hwnd = ((PyObject_Window*)self)->hwnd; 522 | if(!hwnd) 523 | { 524 | PyErr_SetString( PyExc_ValueError, "invalid window object." ); 525 | return NULL; 526 | } 527 | 528 | hwnd = ::GetWindow( hwnd, GW_HWNDNEXT ); 529 | return WindowObject_FromHWND(hwnd); 530 | } 531 | 532 | static PyObject * Window_getParent(PyObject* self, PyObject* args) 533 | { 534 | if( ! PyArg_ParseTuple(args, "" ) ) 535 | return NULL; 536 | 537 | HWND hwnd = ((PyObject_Window*)self)->hwnd; 538 | if(!hwnd) 539 | { 540 | PyErr_SetString( PyExc_ValueError, "invalid window object." ); 541 | return NULL; 542 | } 543 | 544 | hwnd = ::GetAncestor( hwnd, GA_PARENT ); 545 | return WindowObject_FromHWND(hwnd); 546 | } 547 | 548 | static PyObject * Window_getOwner(PyObject* self, PyObject* args) 549 | { 550 | if( ! PyArg_ParseTuple(args, "" ) ) 551 | return NULL; 552 | 553 | HWND hwnd = ((PyObject_Window*)self)->hwnd; 554 | if(!hwnd) 555 | { 556 | PyErr_SetString( PyExc_ValueError, "invalid window object." ); 557 | return NULL; 558 | } 559 | 560 | hwnd = ::GetWindow( hwnd, GW_OWNER ); 561 | return WindowObject_FromHWND(hwnd); 562 | } 563 | 564 | static PyObject * Window_getLastActivePopup(PyObject* self, PyObject* args) 565 | { 566 | if( ! PyArg_ParseTuple(args, "" ) ) 567 | return NULL; 568 | 569 | HWND hwnd = ((PyObject_Window*)self)->hwnd; 570 | if(!hwnd) 571 | { 572 | PyErr_SetString( PyExc_ValueError, "invalid window object." ); 573 | return NULL; 574 | } 575 | 576 | hwnd = ::GetLastActivePopup(hwnd); 577 | return WindowObject_FromHWND(hwnd); 578 | } 579 | 580 | static PyObject * Window_isVisible(PyObject* self, PyObject* args) 581 | { 582 | if( ! PyArg_ParseTuple(args, "" ) ) 583 | return NULL; 584 | 585 | HWND hwnd = ((PyObject_Window*)self)->hwnd; 586 | if(!hwnd) 587 | { 588 | PyErr_SetString( PyExc_ValueError, "invalid window object." ); 589 | return NULL; 590 | } 591 | 592 | if(::IsWindowVisible( hwnd )) 593 | { 594 | Py_INCREF(Py_True); 595 | return Py_True; 596 | } 597 | else 598 | { 599 | Py_INCREF(Py_False); 600 | return Py_False; 601 | } 602 | } 603 | 604 | static PyObject * Window_isEnabled(PyObject* self, PyObject* args) 605 | { 606 | if( ! PyArg_ParseTuple(args, "" ) ) 607 | return NULL; 608 | 609 | HWND hwnd = ((PyObject_Window*)self)->hwnd; 610 | if(!hwnd) 611 | { 612 | PyErr_SetString( PyExc_ValueError, "invalid window object." ); 613 | return NULL; 614 | } 615 | 616 | if(::IsWindowEnabled( hwnd )) 617 | { 618 | Py_INCREF(Py_True); 619 | return Py_True; 620 | } 621 | else 622 | { 623 | Py_INCREF(Py_False); 624 | return Py_False; 625 | } 626 | } 627 | 628 | static PyObject * Window_isMinimized(PyObject* self, PyObject* args) 629 | { 630 | if( ! PyArg_ParseTuple(args, "" ) ) 631 | return NULL; 632 | 633 | HWND hwnd = ((PyObject_Window*)self)->hwnd; 634 | if(!hwnd) 635 | { 636 | PyErr_SetString( PyExc_ValueError, "invalid window object." ); 637 | return NULL; 638 | } 639 | 640 | if(::IsIconic( hwnd )) 641 | { 642 | Py_INCREF(Py_True); 643 | return Py_True; 644 | } 645 | else 646 | { 647 | Py_INCREF(Py_False); 648 | return Py_False; 649 | } 650 | } 651 | 652 | static PyObject * Window_isMaximized(PyObject* self, PyObject* args) 653 | { 654 | if( ! PyArg_ParseTuple(args, "" ) ) 655 | return NULL; 656 | 657 | HWND hwnd = ((PyObject_Window*)self)->hwnd; 658 | if(!hwnd) 659 | { 660 | PyErr_SetString( PyExc_ValueError, "invalid window object." ); 661 | return NULL; 662 | } 663 | 664 | if(::IsZoomed( hwnd )) 665 | { 666 | Py_INCREF(Py_True); 667 | return Py_True; 668 | } 669 | else 670 | { 671 | Py_INCREF(Py_False); 672 | return Py_False; 673 | } 674 | } 675 | 676 | static PyObject * Window_minimize(PyObject* self, PyObject* args) 677 | { 678 | if( ! PyArg_ParseTuple(args, "" ) ) 679 | return NULL; 680 | 681 | HWND hwnd = ((PyObject_Window*)self)->hwnd; 682 | if(!hwnd) 683 | { 684 | PyErr_SetString( PyExc_ValueError, "invalid window object." ); 685 | return NULL; 686 | } 687 | 688 | if( ::SendMessage( hwnd, WM_SYSCOMMAND, SC_MINIMIZE, 0 )==0 ) 689 | { 690 | Py_INCREF(Py_None); 691 | return Py_None; 692 | } 693 | else 694 | { 695 | PyErr_SetFromWindowsErr(0); 696 | return NULL; 697 | } 698 | } 699 | 700 | static PyObject * Window_maximize(PyObject* self, PyObject* args) 701 | { 702 | if( ! PyArg_ParseTuple(args, "" ) ) 703 | return NULL; 704 | 705 | HWND hwnd = ((PyObject_Window*)self)->hwnd; 706 | if(!hwnd) 707 | { 708 | PyErr_SetString( PyExc_ValueError, "invalid window object." ); 709 | return NULL; 710 | } 711 | 712 | if( ::SendMessage( hwnd, WM_SYSCOMMAND, SC_MAXIMIZE, 0 )==0 ) 713 | { 714 | Py_INCREF(Py_None); 715 | return Py_None; 716 | } 717 | else 718 | { 719 | PyErr_SetFromWindowsErr(0); 720 | return NULL; 721 | } 722 | } 723 | 724 | static PyObject * Window_restore(PyObject* self, PyObject* args) 725 | { 726 | if( ! PyArg_ParseTuple(args, "" ) ) 727 | return NULL; 728 | 729 | HWND hwnd = ((PyObject_Window*)self)->hwnd; 730 | if(!hwnd) 731 | { 732 | PyErr_SetString( PyExc_ValueError, "invalid window object." ); 733 | return NULL; 734 | } 735 | 736 | if( ::SendMessage( hwnd, WM_SYSCOMMAND, SC_RESTORE, 0 )==0 ) 737 | { 738 | Py_INCREF(Py_None); 739 | return Py_None; 740 | } 741 | else 742 | { 743 | PyErr_SetFromWindowsErr(0); 744 | return NULL; 745 | } 746 | } 747 | 748 | static PyObject * Window_getCheck(PyObject* self, PyObject* args) 749 | { 750 | if( ! PyArg_ParseTuple(args, "" ) ) 751 | return NULL; 752 | 753 | HWND hwnd = ((PyObject_Window*)self)->hwnd; 754 | if(!hwnd) 755 | { 756 | PyErr_SetString( PyExc_ValueError, "invalid window object." ); 757 | return NULL; 758 | } 759 | 760 | LRESULT result = ::SendMessage( hwnd, BM_GETCHECK, 0, 0 ); 761 | 762 | switch(result) 763 | { 764 | case BST_CHECKED: 765 | return Py_BuildValue( "i", 1 ); 766 | 767 | case BST_INDETERMINATE: 768 | return Py_BuildValue( "i", 2 ); 769 | 770 | default: 771 | return Py_BuildValue( "i", 0 ); 772 | } 773 | } 774 | 775 | static PyObject * Window_setCheck(PyObject* self, PyObject* args) 776 | { 777 | int state; 778 | 779 | if( ! PyArg_ParseTuple(args, "i", &state ) ) 780 | return NULL; 781 | 782 | HWND hwnd = ((PyObject_Window*)self)->hwnd; 783 | if(!hwnd) 784 | { 785 | PyErr_SetString( PyExc_ValueError, "invalid window object." ); 786 | return NULL; 787 | } 788 | 789 | WPARAM bst; 790 | switch(state) 791 | { 792 | case 0: 793 | bst = BST_UNCHECKED; 794 | break; 795 | 796 | case 1: 797 | bst = BST_CHECKED; 798 | break; 799 | 800 | case 2: 801 | bst = BST_INDETERMINATE; 802 | break; 803 | 804 | default: 805 | PyErr_SetString( PyExc_ValueError, "invalid argument." ); 806 | return NULL; 807 | } 808 | 809 | ::SendMessage( hwnd, BM_SETCHECK, bst, 0 ); 810 | 811 | Py_INCREF(Py_None); 812 | return Py_None; 813 | } 814 | 815 | static PyObject * Window_postMessage( PyObject * self, PyObject * args ) 816 | { 817 | int msg_id = 0; 818 | int msg_wparam = 0; 819 | int msg_lparam = 0; 820 | 821 | if( ! PyArg_ParseTuple(args,"i|ii", &msg_id, &msg_wparam, &msg_lparam ) ) 822 | return NULL; 823 | 824 | HWND hwnd = ((PyObject_Window*)self)->hwnd; 825 | if(!hwnd) 826 | { 827 | PyErr_SetString( PyExc_ValueError, "invalid window object." ); 828 | return NULL; 829 | } 830 | 831 | if(::PostMessage( hwnd, msg_id, msg_wparam, msg_lparam )) 832 | { 833 | Py_INCREF(Py_None); 834 | return Py_None; 835 | } 836 | else 837 | { 838 | PyErr_SetFromWindowsErr(0); 839 | return NULL; 840 | } 841 | } 842 | 843 | static PyObject * Window_sendMessage( PyObject * self, PyObject * args ) 844 | { 845 | int msg_id = 0; 846 | int msg_wparam = 0; 847 | int msg_lparam = 0; 848 | 849 | if( ! PyArg_ParseTuple(args,"i|ii", &msg_id, &msg_wparam, &msg_lparam ) ) 850 | return NULL; 851 | 852 | HWND hwnd = ((PyObject_Window*)self)->hwnd; 853 | if(!hwnd) 854 | { 855 | PyErr_SetString( PyExc_ValueError, "invalid window object." ); 856 | return NULL; 857 | } 858 | 859 | LRESULT result = ::SendMessage( hwnd, msg_id, msg_wparam, msg_lparam ); 860 | 861 | return Py_BuildValue( "i", result ); 862 | } 863 | 864 | static PyObject * Window_setForeground( PyObject * self, PyObject * args ) 865 | { 866 | int force = 0; 867 | 868 | if( ! PyArg_ParseTuple( args, "|i", &force ) ) 869 | return NULL; 870 | 871 | HWND hwnd = ((PyObject_Window*)self)->hwnd; 872 | if(!hwnd) 873 | { 874 | PyErr_SetString( PyExc_ValueError, "invalid window object." ); 875 | return NULL; 876 | } 877 | 878 | // 強制的なフォアグラウンド化 879 | { 880 | DWORD error = 0; 881 | 882 | int nTargetID, nForegroundID; 883 | DWORD sp_time = 0; 884 | 885 | bool thread_attached = false; 886 | bool fg_locktime_got = false; 887 | bool fg_locktime_set = false; 888 | 889 | // フォアグラウンドウィンドウを作成したスレッドのIDを取得 890 | nForegroundID = GetWindowThreadProcessId(GetForegroundWindow(), NULL); 891 | 892 | // 目的のウィンドウを作成したスレッドのIDを取得 893 | nTargetID = GetWindowThreadProcessId(hwnd, NULL ); 894 | 895 | if(force && nForegroundID!=nTargetID) 896 | { 897 | // スレッドのインプット状態を結び付ける 898 | if( AttachThreadInput( nTargetID, nForegroundID, TRUE ) ) 899 | { 900 | thread_attached = true; 901 | } 902 | else 903 | { 904 | printf("AttachThreadInput failed %d\n",GetLastError()); 905 | } 906 | 907 | // 現在の設定を sp_time に保存 908 | if( ! SystemParametersInfo( SPI_GETFOREGROUNDLOCKTIMEOUT,0,&sp_time,0) ) 909 | { 910 | printf("SystemParametersInfo(SPI_GETFOREGROUNDLOCKTIMEOUT) failed %d\n",GetLastError()); 911 | 912 | fg_locktime_got = true; 913 | } 914 | 915 | // ウィンドウの切り替え時間を 0ms にする 916 | if(fg_locktime_got) 917 | { 918 | if( ! SystemParametersInfo( SPI_SETFOREGROUNDLOCKTIMEOUT,0,(LPVOID)0,0) ) 919 | { 920 | printf("SystemParametersInfo(SPI_SETFOREGROUNDLOCKTIMEOUT) failed %d\n",GetLastError()); 921 | 922 | fg_locktime_set = true; 923 | } 924 | } 925 | } 926 | 927 | // ウィンドウをフォアグラウンドに持ってくる 928 | if( ! SetForegroundWindow(hwnd) ) 929 | { 930 | printf("SetForegroundWindow failed %d\n",GetLastError()); 931 | 932 | error = GetLastError(); 933 | } 934 | 935 | if(force && nForegroundID!=nTargetID) 936 | { 937 | // 設定を元に戻す 938 | if(fg_locktime_got && fg_locktime_set) 939 | { 940 | if( ! SystemParametersInfo( SPI_SETFOREGROUNDLOCKTIMEOUT,0,(void*)(intptr_t)sp_time,0) ) 941 | { 942 | printf("SystemParametersInfo(SPI_SETFOREGROUNDLOCKTIMEOUT) failed %d\n",GetLastError()); 943 | } 944 | } 945 | 946 | // スレッドのインプット状態を切り離す 947 | if(thread_attached) 948 | { 949 | if( ! AttachThreadInput(nTargetID, nForegroundID, FALSE ) ) 950 | { 951 | printf("AttachThreadInput failed %d\n",GetLastError()); 952 | } 953 | } 954 | } 955 | 956 | // エラーが起きてたら例外を発行する 957 | if(error) 958 | { 959 | PyErr_SetFromWindowsErr(error); 960 | return NULL; 961 | } 962 | } 963 | 964 | Py_INCREF(Py_None); 965 | return Py_None; 966 | } 967 | 968 | static PyObject * Window_getForeground( PyObject * self, PyObject * args ) 969 | { 970 | if( ! PyArg_ParseTuple(args,"" ) ) 971 | return NULL; 972 | 973 | HWND hwnd = ::GetForegroundWindow(); 974 | return WindowObject_FromHWND(hwnd); 975 | } 976 | 977 | static PyObject * Window_setActive( PyObject * self, PyObject * args ) 978 | { 979 | if( ! PyArg_ParseTuple( args, "" ) ) 980 | return NULL; 981 | 982 | HWND hwnd = ((PyObject_Window*)self)->hwnd; 983 | if(!hwnd) 984 | { 985 | PyErr_SetString( PyExc_ValueError, "invalid window object." ); 986 | return NULL; 987 | } 988 | 989 | SetActiveWindow(hwnd); 990 | 991 | Py_INCREF(Py_None); 992 | return Py_None; 993 | } 994 | 995 | static PyObject * Window_getFocus( PyObject * self, PyObject * args ) 996 | { 997 | if( ! PyArg_ParseTuple(args,"" ) ) 998 | return NULL; 999 | 1000 | GUITHREADINFO info; 1001 | info.cbSize = sizeof(info); 1002 | 1003 | if( !GetGUIThreadInfo( NULL, &info ) ) 1004 | { 1005 | PyErr_SetFromWindowsErr(0); 1006 | return NULL; 1007 | } 1008 | 1009 | return WindowObject_FromHWND(info.hwndFocus); 1010 | } 1011 | 1012 | static PyObject * Window_getCaret( PyObject * self, PyObject * args ) 1013 | { 1014 | if( ! PyArg_ParseTuple(args,"" ) ) 1015 | return NULL; 1016 | 1017 | GUITHREADINFO info; 1018 | info.cbSize = sizeof(info); 1019 | 1020 | if( !GetGUIThreadInfo( NULL, &info ) ) 1021 | { 1022 | PyErr_SetFromWindowsErr(0); 1023 | return NULL; 1024 | } 1025 | 1026 | PyObject * pyret = Py_BuildValue( "O(iiii)", WindowObject_FromHWND(info.hwndCaret), info.rcCaret.left, info.rcCaret.top, info.rcCaret.right, info.rcCaret.bottom ); 1027 | return pyret; 1028 | } 1029 | 1030 | static PyObject * Window_find( PyObject * self, PyObject * args ) 1031 | { 1032 | PyObject * pywindow_class; 1033 | PyObject * pywindow_title; 1034 | 1035 | if( ! PyArg_ParseTuple(args,"OO", &pywindow_class, &pywindow_title ) ) 1036 | return NULL; 1037 | 1038 | const TCHAR * p_window_class = NULL; 1039 | const TCHAR * p_window_title = NULL; 1040 | _tString window_class; 1041 | _tString window_title; 1042 | if(stringutil::PyStringTo_tString( pywindow_class, &window_class )) 1043 | p_window_class = window_class.c_str(); 1044 | if(stringutil::PyStringTo_tString( pywindow_title, &window_title )) 1045 | p_window_title = window_title.c_str(); 1046 | 1047 | HWND hwnd = ::FindWindow( p_window_class, p_window_title ); 1048 | return WindowObject_FromHWND(hwnd); 1049 | } 1050 | 1051 | struct _EnumWindowsData 1052 | { 1053 | PyObject * func; 1054 | PyObject * arg; 1055 | }; 1056 | 1057 | static BOOL CALLBACK _EnumWindowsCallback(HWND hwnd, LPARAM lParam) 1058 | { 1059 | _EnumWindowsData * data = (_EnumWindowsData*)lParam; 1060 | 1061 | PyObject * pyarglist = Py_BuildValue("(OO)", WindowObject_FromHWND(hwnd), data->arg ); 1062 | PyObject * pyresult = PyObject_Call( data->func, pyarglist, NULL ); 1063 | Py_DECREF(pyarglist); 1064 | if(pyresult) 1065 | { 1066 | int result; 1067 | PyArg_Parse(pyresult,"i", &result ); 1068 | Py_DECREF(pyresult); 1069 | return result; 1070 | } 1071 | else 1072 | { 1073 | PyErr_Print(); 1074 | return FALSE; //列挙を中断 1075 | } 1076 | } 1077 | 1078 | static PyObject * Window_enum( PyObject * self, PyObject * args ) 1079 | { 1080 | PyObject * func; 1081 | PyObject * arg; 1082 | 1083 | if( ! PyArg_ParseTuple(args,"OO", &func, &arg ) ) 1084 | return NULL; 1085 | 1086 | _EnumWindowsData data; 1087 | data.func = func; 1088 | data.arg = arg; 1089 | 1090 | ::EnumWindows( _EnumWindowsCallback, (LPARAM)&data ); 1091 | 1092 | Py_INCREF(Py_None); 1093 | return Py_None; 1094 | } 1095 | 1096 | static PyObject * Window_getDesktop( PyObject * self, PyObject * args ) 1097 | { 1098 | if( ! PyArg_ParseTuple(args,"" ) ) 1099 | return NULL; 1100 | 1101 | HWND hwnd = ::GetDesktopWindow(); 1102 | 1103 | return WindowObject_FromHWND(hwnd); 1104 | } 1105 | 1106 | static PyObject * Window_fromHWND( PyObject * self, PyObject * args ) 1107 | { 1108 | HWND hwnd; 1109 | 1110 | if( ! PyArg_ParseTuple( args,"i", &hwnd ) ) 1111 | return NULL; 1112 | 1113 | return WindowObject_FromHWND(hwnd); 1114 | } 1115 | 1116 | static BOOL CALLBACK _EnumMonitorCallback( HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData ) 1117 | { 1118 | PyObject * monitor_info_list = (PyObject*)dwData; 1119 | 1120 | MONITORINFO mi; 1121 | mi.cbSize = sizeof(MONITORINFO); 1122 | GetMonitorInfo(hMonitor, &mi); 1123 | 1124 | PyObject * monitor_info = Py_BuildValue( 1125 | "[[iiii][iiii]i]", 1126 | mi.rcMonitor.left, mi.rcMonitor.top, mi.rcMonitor.right, mi.rcMonitor.bottom, 1127 | mi.rcWork.left, mi.rcWork.top, mi.rcWork.right, mi.rcWork.bottom, 1128 | mi.dwFlags 1129 | ); 1130 | 1131 | PyList_Append( monitor_info_list, monitor_info ); 1132 | 1133 | Py_XDECREF(monitor_info); 1134 | 1135 | return TRUE; 1136 | } 1137 | 1138 | static PyObject * Window_getMonitorInfo( PyObject * self, PyObject * args ) 1139 | { 1140 | if( ! PyArg_ParseTuple(args,"" ) ) 1141 | return NULL; 1142 | 1143 | PyObject * monitor_info_list = PyList_New(0); 1144 | 1145 | EnumDisplayMonitors( NULL, NULL, _EnumMonitorCallback, (LPARAM)monitor_info_list ); 1146 | 1147 | return monitor_info_list; 1148 | } 1149 | 1150 | static void Bitmap_ConvertBGRAtoRGB( char * dst, const char * src, int w, int h, int wb ) 1151 | { 1152 | for( int y=0 ; y>11) * 255 / 0x001f; 1184 | dst[ y*w*3 + x*3 + 1 ] = ((src_pixel & (0x003f<<5))>>5) * 255 / 0x003f; 1185 | dst[ y*w*3 + x*3 + 2 ] = ((src_pixel & (0x001f<<0))>>0) * 255 / 0x001f; 1186 | } 1187 | } 1188 | } 1189 | 1190 | static void Bitmap_GetPixeltoRGB( char * dst, HDC dc, int w, int h ) 1191 | { 1192 | for( int y=0 ; yhwnd; 1210 | if(!hwnd) 1211 | { 1212 | PyErr_SetString( PyExc_ValueError, "invalid window object." ); 1213 | return NULL; 1214 | } 1215 | 1216 | RECT rect; 1217 | ::GetWindowRect(hwnd,&rect); 1218 | 1219 | if( rect.right-rect.left<=0 || rect.bottom-rect.top<=0 ) 1220 | { 1221 | PyObject_Image * pyimg; 1222 | pyimg = PyObject_New( PyObject_Image, &PyType_Image ); 1223 | pyimg->w = 0; 1224 | pyimg->h = 0; 1225 | pyimg->buf = malloc(0); 1226 | pyimg->bufsize = 0; 1227 | return (PyObject*)pyimg; 1228 | } 1229 | 1230 | HDC dc_src = ::GetWindowDC(hwnd); 1231 | HDC dc_dst = ::CreateCompatibleDC(dc_src); 1232 | HBITMAP bitmap = ::CreateCompatibleBitmap( dc_src, rect.right-rect.left, rect.bottom-rect.top ); 1233 | 1234 | ::SelectObject( dc_dst, bitmap ); 1235 | ::SetMapMode( dc_dst, MM_TEXT ); 1236 | ::BitBlt( dc_dst, 0, 0, rect.right-rect.left, rect.bottom-rect.top, dc_src, 0, 0, SRCCOPY ); 1237 | 1238 | BITMAP bm; 1239 | ::GetObject( bitmap, sizeof(bm), &bm ); 1240 | 1241 | unsigned int bufsize = bm.bmWidthBytes * bm.bmHeight; 1242 | void * buf = malloc(bufsize); 1243 | 1244 | ::GetBitmapBits( bitmap, bufsize, buf ); 1245 | 1246 | PyObject_Image * pyimg; 1247 | pyimg = PyObject_New( PyObject_Image, &PyType_Image ); 1248 | pyimg->w = bm.bmWidth; 1249 | pyimg->h = bm.bmHeight; 1250 | pyimg->bufsize = pyimg->w * 3 * pyimg->h; 1251 | pyimg->buf = malloc(pyimg->bufsize); 1252 | 1253 | if(bm.bmBitsPixel==32) 1254 | { 1255 | Bitmap_ConvertBGRAtoRGB( (char*)pyimg->buf, (const char*)buf, bm.bmWidth, bm.bmHeight, bm.bmWidthBytes ); 1256 | } 1257 | else if(bm.bmBitsPixel==24) 1258 | { 1259 | Bitmap_ConvertBGRtoRGB( (char*)pyimg->buf, (const char*)buf, bm.bmWidth, bm.bmHeight, bm.bmWidthBytes ); 1260 | } 1261 | else if(bm.bmBitsPixel==16) 1262 | { 1263 | Bitmap_ConvertBGR565toRGB( (char*)pyimg->buf, (const char*)buf, bm.bmWidth, bm.bmHeight, bm.bmWidthBytes ); 1264 | } 1265 | else 1266 | { 1267 | Bitmap_GetPixeltoRGB( (char*)pyimg->buf, dc_dst, bm.bmWidth, bm.bmHeight ); 1268 | } 1269 | 1270 | free(buf); 1271 | 1272 | DeleteObject(bitmap); 1273 | DeleteDC(dc_dst); 1274 | ReleaseDC(hwnd,dc_src); 1275 | 1276 | return (PyObject*)pyimg; 1277 | } 1278 | 1279 | 1280 | #define IMC_GETCONVERSIONMODE 1 1281 | #define IMC_SETCONVERSIONMODE 2 1282 | #define IMC_GETSENTENCEMODE 3 1283 | #define IMC_SETSENTENCEMODE 4 1284 | #define IMC_GETOPENSTATUS 5 1285 | #define IMC_SETOPENSTATUS 6 1286 | 1287 | static PyObject * Window_getImeStatus( PyObject * self, PyObject * args ) 1288 | { 1289 | if( ! PyArg_ParseTuple(args,"" ) ) 1290 | return NULL; 1291 | 1292 | HWND hwnd = ((PyObject_Window*)self)->hwnd; 1293 | if(!hwnd) 1294 | { 1295 | PyErr_SetString( PyExc_ValueError, "invalid window object." ); 1296 | return NULL; 1297 | } 1298 | 1299 | HWND hwnd_ime = ImmGetDefaultIMEWnd(hwnd); 1300 | if( SendMessage( hwnd_ime, WM_IME_CONTROL, IMC_GETOPENSTATUS, 0 )!=0 ) 1301 | { 1302 | Py_INCREF(Py_True); 1303 | return Py_True; 1304 | } 1305 | else 1306 | { 1307 | Py_INCREF(Py_False); 1308 | return Py_False; 1309 | } 1310 | } 1311 | 1312 | static PyObject * Window_setImeStatus( PyObject * self, PyObject * args ) 1313 | { 1314 | int open; 1315 | 1316 | if( ! PyArg_ParseTuple( args, "i", &open ) ) 1317 | return NULL; 1318 | 1319 | HWND hwnd = ((PyObject_Window*)self)->hwnd; 1320 | if(!hwnd) 1321 | { 1322 | PyErr_SetString( PyExc_ValueError, "invalid window object." ); 1323 | return NULL; 1324 | } 1325 | 1326 | HWND hwnd_ime = ImmGetDefaultIMEWnd(hwnd); 1327 | SendMessage( hwnd_ime, WM_IME_CONTROL, IMC_SETOPENSTATUS, open ? 1 : 0 ); 1328 | 1329 | Py_INCREF(Py_None); 1330 | return Py_None; 1331 | } 1332 | 1333 | #if 0 1334 | static PyObject * Window_isImeConverting(PyObject * self, PyObject * args) 1335 | { 1336 | if (!PyArg_ParseTuple(args, "")) 1337 | return NULL; 1338 | 1339 | HWND hwnd = ((PyObject_Window*)self)->hwnd; 1340 | if (!hwnd) 1341 | { 1342 | PyErr_SetString(PyExc_ValueError, "invalid window object."); 1343 | return NULL; 1344 | } 1345 | 1346 | /* TODO : IMEの未確定文字列があるかどうかを返す 1347 | 1348 | 他プロセスがIME入力中であるかどうかを調査する方法として、 1349 | WM_IME_STARTCOMPOSITION と WM_IME_ENDCOMPOSITION イベントをフックで捉える方法があるが、 1350 | 他プロセスにHook用DLLをインストールする必要があり、32bit/64bit 両サポートが煩雑になるのでやりたくない。 1351 | 1352 | Hook DLL を必要としないやり方で、IME変換中であるかを調べる方法がないか。 1353 | */ 1354 | 1355 | if(ime_converting) 1356 | { 1357 | Py_INCREF(Py_True); 1358 | return Py_True; 1359 | } 1360 | else 1361 | { 1362 | Py_INCREF(Py_False); 1363 | return Py_False; 1364 | } 1365 | } 1366 | #endif 1367 | 1368 | static PyMethodDef Window_methods[] = { 1369 | { "getText", Window_getText, METH_VARARGS, "" }, 1370 | { "getClassName", Window_getClassName, METH_VARARGS, "" }, 1371 | { "getProcessName", Window_getProcessName, METH_VARARGS, "" }, 1372 | { "getProcessPath", Window_getProcessPath, METH_VARARGS, "" }, 1373 | { "getHWND", Window_getHWND, METH_VARARGS, "" }, 1374 | { "getRect", Window_getRect, METH_VARARGS, "" }, 1375 | { "setRect", Window_setRect, METH_VARARGS, "" }, 1376 | { "getClientRect", Window_getClientRect, METH_VARARGS, "" }, 1377 | { "clientToScreen", Window_clientToScreen, METH_VARARGS, "" }, 1378 | { "getFirstChild", Window_getFirstChild, METH_VARARGS, "" }, 1379 | { "getLastChild", Window_getLastChild, METH_VARARGS, "" }, 1380 | { "getPrevious", Window_getPrevious, METH_VARARGS, "" }, 1381 | { "getNext", Window_getNext, METH_VARARGS, "" }, 1382 | { "getParent", Window_getParent, METH_VARARGS, "" }, 1383 | { "getOwner", Window_getOwner, METH_VARARGS, "" }, 1384 | { "getLastActivePopup", Window_getLastActivePopup, METH_VARARGS, "" }, 1385 | { "isVisible", Window_isVisible, METH_VARARGS, "" }, 1386 | { "isEnabled", Window_isEnabled, METH_VARARGS, "" }, 1387 | { "isMinimized", Window_isMinimized, METH_VARARGS, "" }, 1388 | { "isMaximized", Window_isMaximized, METH_VARARGS, "" }, 1389 | { "minimize", Window_minimize, METH_VARARGS, "" }, 1390 | { "maximize", Window_maximize, METH_VARARGS, "" }, 1391 | { "restore", Window_restore, METH_VARARGS, "" }, 1392 | { "getCheck", Window_getCheck, METH_VARARGS, "" }, 1393 | { "setCheck", Window_setCheck, METH_VARARGS, "" }, 1394 | { "postMessage", Window_postMessage, METH_VARARGS, "" }, 1395 | { "sendMessage", Window_sendMessage, METH_VARARGS, "" }, 1396 | { "setForeground", Window_setForeground, METH_VARARGS, "" }, 1397 | { "getForeground", Window_getForeground, METH_STATIC|METH_VARARGS, "" }, 1398 | { "setActive", Window_setActive, METH_VARARGS, "" }, 1399 | { "getFocus", Window_getFocus, METH_STATIC|METH_VARARGS, "" }, 1400 | { "getCaret", Window_getCaret, METH_STATIC|METH_VARARGS, "" }, 1401 | { "find", Window_find, METH_STATIC|METH_VARARGS, "" }, 1402 | { "enum", Window_enum, METH_STATIC|METH_VARARGS, "" }, 1403 | { "getDesktop", Window_getDesktop, METH_STATIC|METH_VARARGS, "" }, 1404 | { "fromHWND", Window_fromHWND, METH_STATIC|METH_VARARGS, "" }, 1405 | { "getMonitorInfo", Window_getMonitorInfo, METH_STATIC|METH_VARARGS, "" }, 1406 | { "getImage", Window_getImage, METH_VARARGS, "" }, 1407 | { "getImeStatus", Window_getImeStatus, METH_VARARGS, "" }, 1408 | { "setImeStatus", Window_setImeStatus, METH_VARARGS, "" }, 1409 | {NULL,NULL} 1410 | }; 1411 | 1412 | PyTypeObject pyauto::PyType_Window = { 1413 | PyVarObject_HEAD_INIT(NULL, 0) 1414 | "Window", /* tp_name */ 1415 | sizeof(PyObject_Window), /* tp_basicsize */ 1416 | 0, /* tp_itemsize */ 1417 | Window_dealloc, /* tp_dealloc */ 1418 | 0, /* tp_print */ 1419 | 0, /* tp_getattr */ 1420 | 0, /* tp_setattr */ 1421 | 0, /* tp_compare */ 1422 | 0, /* tp_repr */ 1423 | 0, /* tp_as_number */ 1424 | 0, /* tp_as_sequence */ 1425 | 0, /* tp_as_mapping */ 1426 | 0, /* tp_hash */ 1427 | 0, /* tp_call */ 1428 | 0, /* tp_str */ 1429 | PyObject_GenericGetAttr,/* tp_getattro */ 1430 | PyObject_GenericSetAttr,/* tp_setattro */ 1431 | 0, /* tp_as_buffer */ 1432 | Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,/* tp_flags */ 1433 | "", /* tp_doc */ 1434 | 0, /* tp_traverse */ 1435 | 0, /* tp_clear */ 1436 | 0, /* tp_richcompare */ 1437 | 0, /* tp_weaklistoffset */ 1438 | 0, /* tp_iter */ 1439 | 0, /* tp_iternext */ 1440 | Window_methods, /* tp_methods */ 1441 | 0, /* tp_members */ 1442 | 0, /* tp_getset */ 1443 | 0, /* tp_base */ 1444 | 0, /* tp_dict */ 1445 | 0, /* tp_descr_get */ 1446 | 0, /* tp_descr_set */ 1447 | 0, /* tp_dictoffset */ 1448 | 0, /* tp_init */ 1449 | 0, /* tp_alloc */ 1450 | PyType_GenericNew, /* tp_new */ 1451 | 0, /* tp_free */ 1452 | }; 1453 | 1454 | // ------------ PyObject_Image ----------------------------------------- 1455 | 1456 | static void Image_dealloc(PyObject* self) 1457 | { 1458 | free(((PyObject_Image*)self)->buf); 1459 | self->ob_type->tp_free(self); 1460 | } 1461 | 1462 | static PyObject * Image_getSize(PyObject* self, PyObject* args) 1463 | { 1464 | if( ! PyArg_ParseTuple(args, "" ) ) 1465 | return NULL; 1466 | return Py_BuildValue( "(ii)", ((PyObject_Image*)self)->w, ((PyObject_Image*)self)->h ); 1467 | } 1468 | 1469 | static PyObject * Image_getMode(PyObject* self, PyObject* args) 1470 | { 1471 | if( ! PyArg_ParseTuple(args, "" ) ) 1472 | return NULL; 1473 | return Py_BuildValue( "s", "RGB" ); 1474 | } 1475 | 1476 | static PyObject * Image_getBuffer(PyObject* self, PyObject* args) 1477 | { 1478 | if( ! PyArg_ParseTuple(args, "" ) ) 1479 | return NULL; 1480 | return Py_BuildValue( "y#", ((PyObject_Image*)self)->buf, ((PyObject_Image*)self)->bufsize ); 1481 | } 1482 | 1483 | static PyObject * Image_fromString( PyObject * self, PyObject * args ) 1484 | { 1485 | const char * mode; 1486 | int width; 1487 | int height; 1488 | const char * buf; 1489 | Py_ssize_t bufsize; 1490 | 1491 | if( ! PyArg_ParseTuple(args,"s(ii)y#", &mode, &width, &height, &buf, &bufsize ) ) 1492 | return NULL; 1493 | 1494 | if( strcmp( mode, "RGB" )!=0 ) 1495 | { 1496 | PyErr_SetString( PyExc_ValueError, "image mode unsupported." ); 1497 | return NULL; 1498 | } 1499 | 1500 | if( (unsigned)(width * 3 * height) > bufsize ) 1501 | { 1502 | PyErr_SetString( PyExc_ValueError, "insufficient buffer length." ); 1503 | return NULL; 1504 | } 1505 | 1506 | if( width<=0 || height<=0 ) 1507 | { 1508 | PyObject_Image * pyimg; 1509 | pyimg = PyObject_New( PyObject_Image, &PyType_Image ); 1510 | pyimg->w = 0; 1511 | pyimg->h = 0; 1512 | pyimg->buf = malloc(0); 1513 | pyimg->bufsize = 0; 1514 | return (PyObject*)pyimg; 1515 | } 1516 | 1517 | PyObject_Image * pyimg; 1518 | pyimg = PyObject_New( PyObject_Image, &PyType_Image ); 1519 | pyimg->w = width; 1520 | pyimg->h = height; 1521 | pyimg->bufsize = pyimg->w * 3 * pyimg->h; 1522 | pyimg->buf = malloc(pyimg->bufsize); 1523 | 1524 | memcpy( pyimg->buf, buf, pyimg->bufsize ); 1525 | 1526 | return (PyObject*)pyimg; 1527 | } 1528 | 1529 | static PyObject * Image_find( PyObject * self, PyObject * args ) 1530 | { 1531 | PyObject * obj; 1532 | 1533 | if( ! PyArg_ParseTuple(args,"O", &obj ) ) 1534 | return NULL; 1535 | 1536 | if( ! TypeCheck_Image(obj) ) 1537 | { 1538 | PyErr_SetString( PyExc_TypeError, "first argument must be a pyautocore.Image object." ); 1539 | return NULL; 1540 | } 1541 | 1542 | PyObject_Image * img1 = (PyObject_Image*)self; 1543 | PyObject_Image * img2 = (PyObject_Image*)obj; 1544 | 1545 | bool found = false; 1546 | int x, y; 1547 | 1548 | for( y=0 ; y<=img1->h-img2->h ; y++ ) 1549 | { 1550 | for( x=0 ; x<=img1->w-img2->w ; x++ ) 1551 | { 1552 | bool failed = false; 1553 | 1554 | for( int y2=0 ; y2h ; y2++ ) 1555 | { 1556 | for( int x2=0 ; x2w ; x2++ ) 1557 | { 1558 | int x1 = x+x2; 1559 | int y1 = y+y2; 1560 | if( ((const char*)img1->buf)[ y1 * img1->w * 3 + x1 * 3 + 0 ] != ((const char*)img2->buf)[ y2 * img2->w * 3 + x2 * 3 + 0 ] 1561 | || ((const char*)img1->buf)[ y1 * img1->w * 3 + x1 * 3 + 1 ] != ((const char*)img2->buf)[ y2 * img2->w * 3 + x2 * 3 + 1 ] 1562 | || ((const char*)img1->buf)[ y1 * img1->w * 3 + x1 * 3 + 2 ] != ((const char*)img2->buf)[ y2 * img2->w * 3 + x2 * 3 + 2 ] ) 1563 | { 1564 | failed = true; 1565 | } 1566 | 1567 | if(failed) break; 1568 | } 1569 | 1570 | if(failed) break; 1571 | } 1572 | 1573 | if( ! failed ) 1574 | { 1575 | found = true; 1576 | break; 1577 | } 1578 | } 1579 | 1580 | if(found) break; 1581 | } 1582 | 1583 | if(found) 1584 | { 1585 | PyObject * pyret = Py_BuildValue( "(ii)", x, y ); 1586 | return pyret; 1587 | } 1588 | else 1589 | { 1590 | Py_INCREF(Py_None); 1591 | return Py_None; 1592 | } 1593 | } 1594 | 1595 | static PyMethodDef Image_methods[] = { 1596 | { "getSize", Image_getSize, METH_VARARGS, "" }, 1597 | { "getMode", Image_getMode, METH_VARARGS, "" }, 1598 | { "getBuffer", Image_getBuffer, METH_VARARGS, "" }, 1599 | { "fromString", Image_fromString, METH_STATIC|METH_VARARGS, "" }, 1600 | { "find", Image_find, METH_VARARGS, "" }, 1601 | {NULL,NULL} 1602 | }; 1603 | 1604 | PyTypeObject pyauto::PyType_Image = { 1605 | PyVarObject_HEAD_INIT(NULL, 0) 1606 | "Image", /* tp_name */ 1607 | sizeof(PyObject_Image), /* tp_basicsize */ 1608 | 0, /* tp_itemsize */ 1609 | Image_dealloc, /* tp_dealloc */ 1610 | 0, /* tp_print */ 1611 | 0, /* tp_getattr */ 1612 | 0, /* tp_setattr */ 1613 | 0, /* tp_compare */ 1614 | 0, /* tp_repr */ 1615 | 0, /* tp_as_number */ 1616 | 0, /* tp_as_sequence */ 1617 | 0, /* tp_as_mapping */ 1618 | 0, /* tp_hash */ 1619 | 0, /* tp_call */ 1620 | 0, /* tp_str */ 1621 | PyObject_GenericGetAttr,/* tp_getattro */ 1622 | PyObject_GenericSetAttr,/* tp_setattro */ 1623 | 0, /* tp_as_buffer */ 1624 | Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,/* tp_flags */ 1625 | "", /* tp_doc */ 1626 | 0, /* tp_traverse */ 1627 | 0, /* tp_clear */ 1628 | 0, /* tp_richcompare */ 1629 | 0, /* tp_weaklistoffset */ 1630 | 0, /* tp_iter */ 1631 | 0, /* tp_iternext */ 1632 | Image_methods, /* tp_methods */ 1633 | 0, /* tp_members */ 1634 | 0, /* tp_getset */ 1635 | 0, /* tp_base */ 1636 | 0, /* tp_dict */ 1637 | 0, /* tp_descr_get */ 1638 | 0, /* tp_descr_set */ 1639 | 0, /* tp_dictoffset */ 1640 | 0, /* tp_init */ 1641 | 0, /* tp_alloc */ 1642 | PyType_GenericNew, /* tp_new */ 1643 | 0, /* tp_free */ 1644 | }; 1645 | 1646 | // ------------ PyObject_Input ----------------------------------------- 1647 | 1648 | static int Input_init( PyObject * self, PyObject * args, PyObject * kwds) 1649 | { 1650 | if( ! PyArg_ParseTuple( args, "" ) ) 1651 | return -1; 1652 | 1653 | ((PyObject_Input*)self)->num = 0; 1654 | 1655 | return 0; 1656 | } 1657 | 1658 | #if !defined(_MSC_VER) 1659 | # define _snprintf_s( a, b, c, ... ) snprintf( a, b, __VA_ARGS__ ) 1660 | #endif 1661 | 1662 | static PyObject * Input_repr( PyObject * self ) 1663 | { 1664 | char buf[64]; 1665 | buf[0] = 0; 1666 | 1667 | switch( ((PyObject_Input*)self)->num ) 1668 | { 1669 | case 0: 1670 | break; 1671 | 1672 | case 1: 1673 | { 1674 | INPUT & input = ((PyObject_Input*)self)->input[0]; 1675 | 1676 | switch(input.type) 1677 | { 1678 | case INPUT_KEYBOARD: 1679 | { 1680 | if( input.ki.dwFlags & KEYEVENTF_UNICODE ) 1681 | { 1682 | _snprintf_s( buf, sizeof(buf), _TRUNCATE, "Char(%d)", input.ki.wScan ); 1683 | } 1684 | else if( input.ki.dwFlags & KEYEVENTF_KEYUP ) 1685 | { 1686 | _snprintf_s( buf, sizeof(buf), _TRUNCATE, "KeyUp(%d)", input.ki.wVk ); 1687 | } 1688 | else 1689 | { 1690 | _snprintf_s( buf, sizeof(buf), _TRUNCATE, "KeyDown(%d)", input.ki.wVk ); 1691 | } 1692 | } 1693 | break; 1694 | 1695 | case INPUT_MOUSE: 1696 | { 1697 | if( input.mi.dwFlags & MOUSEEVENTF_LEFTDOWN ) 1698 | { 1699 | _snprintf_s( buf, sizeof(buf), _TRUNCATE, "MouseLeftDown(%d,%d)", input.mi.dx, input.mi.dy ); 1700 | } 1701 | else if( input.mi.dwFlags & MOUSEEVENTF_LEFTUP ) 1702 | { 1703 | _snprintf_s( buf, sizeof(buf), _TRUNCATE, "MouseLeftUp(%d,%d)", input.mi.dx, input.mi.dy ); 1704 | } 1705 | else if( input.mi.dwFlags & MOUSEEVENTF_RIGHTDOWN ) 1706 | { 1707 | _snprintf_s( buf, sizeof(buf), _TRUNCATE, "MouseRightDown(%d,%d)", input.mi.dx, input.mi.dy ); 1708 | } 1709 | else if( input.mi.dwFlags & MOUSEEVENTF_RIGHTUP ) 1710 | { 1711 | _snprintf_s( buf, sizeof(buf), _TRUNCATE, "MouseRightUp(%d,%d)", input.mi.dx, input.mi.dy ); 1712 | } 1713 | else if( input.mi.dwFlags & MOUSEEVENTF_MIDDLEDOWN ) 1714 | { 1715 | _snprintf_s( buf, sizeof(buf), _TRUNCATE, "MouseMiddleDown(%d,%d)", input.mi.dx, input.mi.dy ); 1716 | } 1717 | else if( input.mi.dwFlags & MOUSEEVENTF_MIDDLEUP ) 1718 | { 1719 | _snprintf_s( buf, sizeof(buf), _TRUNCATE, "MouseMiddleUp(%d,%d)", input.mi.dx, input.mi.dy ); 1720 | } 1721 | else if( input.mi.dwFlags & MOUSEEVENTF_WHEEL ) 1722 | { 1723 | _snprintf_s( buf, sizeof(buf), _TRUNCATE, "MouseWheel(%d,%d,%d)", input.mi.dx, input.mi.dy, input.mi.mouseData ); 1724 | } 1725 | else if( input.mi.dwFlags & MOUSEEVENTF_HWHEEL ) 1726 | { 1727 | _snprintf_s( buf, sizeof(buf), _TRUNCATE, "MouseHorizontalWheel(%d,%d,%d)", input.mi.dx, input.mi.dy, input.mi.mouseData ); 1728 | } 1729 | else 1730 | { 1731 | _snprintf_s( buf, sizeof(buf), _TRUNCATE, "MouseMove(%d,%d)", input.mi.dx, input.mi.dy ); 1732 | } 1733 | } 1734 | break; 1735 | } 1736 | } 1737 | break; 1738 | 1739 | case 2: 1740 | { 1741 | INPUT & input = ((PyObject_Input*)self)->input[0]; 1742 | 1743 | switch(input.type) 1744 | { 1745 | case INPUT_KEYBOARD: 1746 | { 1747 | _snprintf_s( buf, sizeof(buf), _TRUNCATE, "Key(%d)", input.ki.wVk ); 1748 | } 1749 | break; 1750 | 1751 | case INPUT_MOUSE: 1752 | { 1753 | if( input.mi.dwFlags & MOUSEEVENTF_LEFTDOWN ) 1754 | { 1755 | _snprintf_s( buf, sizeof(buf), _TRUNCATE, "MouseLeftClick(%d,%d)", input.mi.dx, input.mi.dy ); 1756 | } 1757 | else if( input.mi.dwFlags & MOUSEEVENTF_RIGHTDOWN ) 1758 | { 1759 | _snprintf_s( buf, sizeof(buf), _TRUNCATE, "MouseRightClick(%d,%d)", input.mi.dx, input.mi.dy ); 1760 | } 1761 | else if( input.mi.dwFlags & MOUSEEVENTF_MIDDLEDOWN ) 1762 | { 1763 | _snprintf_s( buf, sizeof(buf), _TRUNCATE, "MouseMiddleClick(%d,%d)", input.mi.dx, input.mi.dy ); 1764 | } 1765 | } 1766 | break; 1767 | } 1768 | } 1769 | break; 1770 | } 1771 | 1772 | if(buf[0]==0) 1773 | { 1774 | _snprintf_s( buf, sizeof(buf), _TRUNCATE, "" ); 1775 | } 1776 | 1777 | PyObject * pyret = Py_BuildValue( "s", buf ); 1778 | return pyret; 1779 | } 1780 | 1781 | static int IsExtendedKey( int vk ) 1782 | { 1783 | switch(vk) 1784 | { 1785 | case VK_CANCEL: 1786 | case VK_PRIOR: 1787 | case VK_NEXT: 1788 | case VK_END: 1789 | case VK_HOME: 1790 | case VK_LEFT: 1791 | case VK_UP: 1792 | case VK_RIGHT: 1793 | case VK_DOWN: 1794 | case VK_SNAPSHOT: 1795 | case VK_INSERT: 1796 | case VK_DELETE: 1797 | case VK_DIVIDE: 1798 | case VK_NUMLOCK: 1799 | case VK_RSHIFT: 1800 | case VK_RCONTROL: 1801 | case VK_RMENU: 1802 | return true; 1803 | 1804 | default: 1805 | return false; 1806 | } 1807 | } 1808 | 1809 | static PyObject * Input_setKeyDown(PyObject* self, PyObject* args) 1810 | { 1811 | int vk; 1812 | 1813 | if( ! PyArg_ParseTuple(args, "i", &vk ) ) 1814 | return NULL; 1815 | 1816 | ((PyObject_Input*)self)->num = 1; 1817 | 1818 | INPUT & input = ((PyObject_Input*)self)->input[0]; 1819 | input.type = INPUT_KEYBOARD; 1820 | input.ki.wVk = (WORD)vk; 1821 | input.ki.wScan = MapVirtualKey(vk,0); 1822 | input.ki.dwFlags = (IsExtendedKey(vk) ? KEYEVENTF_EXTENDEDKEY : 0); 1823 | input.ki.dwExtraInfo = 0; 1824 | input.ki.time = 0; 1825 | 1826 | Py_INCREF(Py_None); 1827 | return Py_None; 1828 | } 1829 | 1830 | static PyObject * Input_setKeyUp(PyObject* self, PyObject* args) 1831 | { 1832 | int vk; 1833 | 1834 | if( ! PyArg_ParseTuple(args, "i", &vk ) ) 1835 | return NULL; 1836 | 1837 | ((PyObject_Input*)self)->num = 1; 1838 | 1839 | INPUT & input = ((PyObject_Input*)self)->input[0]; 1840 | input.type = INPUT_KEYBOARD; 1841 | input.ki.wVk = (WORD)vk; 1842 | input.ki.wScan = MapVirtualKey(vk,0); 1843 | input.ki.dwFlags = KEYEVENTF_KEYUP | (IsExtendedKey(vk) ? KEYEVENTF_EXTENDEDKEY : 0); 1844 | input.ki.dwExtraInfo = 0; 1845 | input.ki.time = 0; 1846 | 1847 | Py_INCREF(Py_None); 1848 | return Py_None; 1849 | } 1850 | 1851 | static PyObject * Input_setKey(PyObject* self, PyObject* args) 1852 | { 1853 | int vk; 1854 | 1855 | if( ! PyArg_ParseTuple(args, "i", &vk ) ) 1856 | return NULL; 1857 | 1858 | ((PyObject_Input*)self)->num = 2; 1859 | 1860 | { 1861 | INPUT & input = ((PyObject_Input*)self)->input[0]; 1862 | input.type = INPUT_KEYBOARD; 1863 | input.ki.wVk = (WORD)vk; 1864 | input.ki.wScan = MapVirtualKey(vk,0); 1865 | input.ki.dwFlags = (IsExtendedKey(vk) ? KEYEVENTF_EXTENDEDKEY : 0); 1866 | input.ki.dwExtraInfo = 0; 1867 | input.ki.time = 0; 1868 | } 1869 | 1870 | { 1871 | INPUT & input = ((PyObject_Input*)self)->input[1]; 1872 | input.type = INPUT_KEYBOARD; 1873 | input.ki.wVk = (WORD)vk; 1874 | input.ki.wScan = MapVirtualKey(vk,0); 1875 | input.ki.dwFlags = KEYEVENTF_KEYUP | (IsExtendedKey(vk) ? KEYEVENTF_EXTENDEDKEY : 0); 1876 | input.ki.dwExtraInfo = 0; 1877 | input.ki.time = 0; 1878 | } 1879 | 1880 | Py_INCREF(Py_None); 1881 | return Py_None; 1882 | } 1883 | 1884 | static PyObject * Input_setChar(PyObject* self, PyObject* args) 1885 | { 1886 | int unicode; 1887 | 1888 | if( ! PyArg_ParseTuple(args, "i", &unicode ) ) 1889 | return NULL; 1890 | 1891 | ((PyObject_Input*)self)->num = 2; 1892 | 1893 | { 1894 | INPUT & input = ((PyObject_Input*)self)->input[0]; 1895 | input.type = INPUT_KEYBOARD; 1896 | input.ki.wVk = 0; 1897 | input.ki.wScan = unicode; 1898 | input.ki.dwFlags = KEYEVENTF_UNICODE; 1899 | input.ki.dwExtraInfo = 0; 1900 | input.ki.time = 0; 1901 | } 1902 | 1903 | { 1904 | INPUT & input = ((PyObject_Input*)self)->input[1]; 1905 | input.type = INPUT_KEYBOARD; 1906 | input.ki.wVk = 0; 1907 | input.ki.wScan = unicode; 1908 | input.ki.dwFlags = KEYEVENTF_UNICODE | KEYEVENTF_KEYUP; 1909 | input.ki.dwExtraInfo = 0; 1910 | input.ki.time = 0; 1911 | } 1912 | 1913 | Py_INCREF(Py_None); 1914 | return Py_None; 1915 | } 1916 | 1917 | static inline int sign( const int & i ) 1918 | { 1919 | if(i==0) return 0; 1920 | else if(i>0) return 1; 1921 | else return -1; 1922 | } 1923 | 1924 | static inline void MousePositionAsPixel( int * x, int * y ) 1925 | { 1926 | *x = (int)(( *x + 0.5f * sign(*x) ) * 65536 / (GetSystemMetrics(SM_CXSCREEN))); 1927 | *y = (int)(( *y + 0.5f * sign(*y) ) * 65536 / (GetSystemMetrics(SM_CYSCREEN))); 1928 | } 1929 | 1930 | static PyObject * Input_setMouseMove(PyObject* self, PyObject* args) 1931 | { 1932 | int x,y; 1933 | 1934 | if( ! PyArg_ParseTuple(args, "ii", &x, &y ) ) 1935 | return NULL; 1936 | 1937 | MousePositionAsPixel( &x, &y ); 1938 | 1939 | ((PyObject_Input*)self)->num = 1; 1940 | 1941 | INPUT & input = ((PyObject_Input*)self)->input[0]; 1942 | input.type = INPUT_MOUSE; 1943 | input.mi.dx = x; 1944 | input.mi.dy = y; 1945 | input.mi.mouseData = 0; 1946 | input.mi.dwFlags = MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE; 1947 | input.mi.dwExtraInfo = 0; 1948 | input.mi.time = 0; 1949 | 1950 | Py_INCREF(Py_None); 1951 | return Py_None; 1952 | } 1953 | 1954 | static PyObject * Input_setMouseLeftDown(PyObject* self, PyObject* args) 1955 | { 1956 | int x,y; 1957 | 1958 | if( ! PyArg_ParseTuple(args, "ii", &x, &y ) ) 1959 | return NULL; 1960 | 1961 | MousePositionAsPixel( &x, &y ); 1962 | 1963 | ((PyObject_Input*)self)->num = 1; 1964 | 1965 | INPUT & input = ((PyObject_Input*)self)->input[0]; 1966 | input.type = INPUT_MOUSE; 1967 | input.mi.dx = x; 1968 | input.mi.dy = y; 1969 | input.mi.mouseData = 0; 1970 | input.mi.dwFlags = MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_LEFTDOWN; 1971 | input.mi.dwExtraInfo = 0; 1972 | input.mi.time = 0; 1973 | 1974 | Py_INCREF(Py_None); 1975 | return Py_None; 1976 | } 1977 | 1978 | static PyObject * Input_setMouseLeftUp(PyObject* self, PyObject* args) 1979 | { 1980 | int x,y; 1981 | 1982 | if( ! PyArg_ParseTuple(args, "ii", &x, &y ) ) 1983 | return NULL; 1984 | 1985 | MousePositionAsPixel( &x, &y ); 1986 | 1987 | ((PyObject_Input*)self)->num = 1; 1988 | 1989 | INPUT & input = ((PyObject_Input*)self)->input[0]; 1990 | input.type = INPUT_MOUSE; 1991 | input.mi.dx = x; 1992 | input.mi.dy = y; 1993 | input.mi.mouseData = 0; 1994 | input.mi.dwFlags = MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_LEFTUP; 1995 | input.mi.dwExtraInfo = 0; 1996 | input.mi.time = 0; 1997 | 1998 | Py_INCREF(Py_None); 1999 | return Py_None; 2000 | } 2001 | 2002 | static PyObject * Input_setMouseLeftClick(PyObject* self, PyObject* args) 2003 | { 2004 | int x,y; 2005 | 2006 | if( ! PyArg_ParseTuple(args, "ii", &x, &y ) ) 2007 | return NULL; 2008 | 2009 | MousePositionAsPixel( &x, &y ); 2010 | 2011 | ((PyObject_Input*)self)->num = 2; 2012 | 2013 | { 2014 | INPUT & input = ((PyObject_Input*)self)->input[0]; 2015 | input.type = INPUT_MOUSE; 2016 | input.mi.dx = x; 2017 | input.mi.dy = y; 2018 | input.mi.mouseData = 0; 2019 | input.mi.dwFlags = MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_LEFTDOWN; 2020 | input.mi.dwExtraInfo = 0; 2021 | input.mi.time = 0; 2022 | } 2023 | 2024 | { 2025 | INPUT & input = ((PyObject_Input*)self)->input[1]; 2026 | input.type = INPUT_MOUSE; 2027 | input.mi.dx = x; 2028 | input.mi.dy = y; 2029 | input.mi.mouseData = 0; 2030 | input.mi.dwFlags = MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_LEFTUP; 2031 | input.mi.dwExtraInfo = 0; 2032 | input.mi.time = 0; 2033 | } 2034 | 2035 | Py_INCREF(Py_None); 2036 | return Py_None; 2037 | } 2038 | 2039 | static PyObject * Input_setMouseRightDown(PyObject* self, PyObject* args) 2040 | { 2041 | int x,y; 2042 | 2043 | if( ! PyArg_ParseTuple(args, "ii", &x, &y ) ) 2044 | return NULL; 2045 | 2046 | MousePositionAsPixel( &x, &y ); 2047 | 2048 | ((PyObject_Input*)self)->num = 1; 2049 | 2050 | INPUT & input = ((PyObject_Input*)self)->input[0]; 2051 | input.type = INPUT_MOUSE; 2052 | input.mi.dx = x; 2053 | input.mi.dy = y; 2054 | input.mi.mouseData = 0; 2055 | input.mi.dwFlags = MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_RIGHTDOWN; 2056 | input.mi.dwExtraInfo = 0; 2057 | input.mi.time = 0; 2058 | 2059 | Py_INCREF(Py_None); 2060 | return Py_None; 2061 | } 2062 | 2063 | static PyObject * Input_setMouseRightUp(PyObject* self, PyObject* args) 2064 | { 2065 | int x,y; 2066 | 2067 | if( ! PyArg_ParseTuple(args, "ii", &x, &y ) ) 2068 | return NULL; 2069 | 2070 | MousePositionAsPixel( &x, &y ); 2071 | 2072 | ((PyObject_Input*)self)->num = 1; 2073 | 2074 | INPUT & input = ((PyObject_Input*)self)->input[0]; 2075 | input.type = INPUT_MOUSE; 2076 | input.mi.dx = x; 2077 | input.mi.dy = y; 2078 | input.mi.mouseData = 0; 2079 | input.mi.dwFlags = MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_RIGHTUP; 2080 | input.mi.dwExtraInfo = 0; 2081 | input.mi.time = 0; 2082 | 2083 | Py_INCREF(Py_None); 2084 | return Py_None; 2085 | } 2086 | 2087 | static PyObject * Input_setMouseRightClick(PyObject* self, PyObject* args) 2088 | { 2089 | int x,y; 2090 | 2091 | if( ! PyArg_ParseTuple(args, "ii", &x, &y ) ) 2092 | return NULL; 2093 | 2094 | MousePositionAsPixel( &x, &y ); 2095 | 2096 | ((PyObject_Input*)self)->num = 2; 2097 | 2098 | { 2099 | INPUT & input = ((PyObject_Input*)self)->input[0]; 2100 | input.type = INPUT_MOUSE; 2101 | input.mi.dx = x; 2102 | input.mi.dy = y; 2103 | input.mi.mouseData = 0; 2104 | input.mi.dwFlags = MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_RIGHTDOWN; 2105 | input.mi.dwExtraInfo = 0; 2106 | input.mi.time = 0; 2107 | } 2108 | 2109 | { 2110 | INPUT & input = ((PyObject_Input*)self)->input[1]; 2111 | input.type = INPUT_MOUSE; 2112 | input.mi.dx = x; 2113 | input.mi.dy = y; 2114 | input.mi.mouseData = 0; 2115 | input.mi.dwFlags = MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_RIGHTUP; 2116 | input.mi.dwExtraInfo = 0; 2117 | input.mi.time = 0; 2118 | } 2119 | 2120 | Py_INCREF(Py_None); 2121 | return Py_None; 2122 | } 2123 | 2124 | static PyObject * Input_setMouseMiddleDown(PyObject* self, PyObject* args) 2125 | { 2126 | int x,y; 2127 | 2128 | if( ! PyArg_ParseTuple(args, "ii", &x, &y ) ) 2129 | return NULL; 2130 | 2131 | MousePositionAsPixel( &x, &y ); 2132 | 2133 | ((PyObject_Input*)self)->num = 1; 2134 | 2135 | INPUT & input = ((PyObject_Input*)self)->input[0]; 2136 | input.type = INPUT_MOUSE; 2137 | input.mi.dx = x; 2138 | input.mi.dy = y; 2139 | input.mi.mouseData = 0; 2140 | input.mi.dwFlags = MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MIDDLEDOWN; 2141 | input.mi.dwExtraInfo = 0; 2142 | input.mi.time = 0; 2143 | 2144 | Py_INCREF(Py_None); 2145 | return Py_None; 2146 | } 2147 | 2148 | static PyObject * Input_setMouseMiddleUp(PyObject* self, PyObject* args) 2149 | { 2150 | int x,y; 2151 | 2152 | if( ! PyArg_ParseTuple(args, "ii", &x, &y ) ) 2153 | return NULL; 2154 | 2155 | MousePositionAsPixel( &x, &y ); 2156 | 2157 | ((PyObject_Input*)self)->num = 1; 2158 | 2159 | INPUT & input = ((PyObject_Input*)self)->input[0]; 2160 | input.type = INPUT_MOUSE; 2161 | input.mi.dx = x; 2162 | input.mi.dy = y; 2163 | input.mi.mouseData = 0; 2164 | input.mi.dwFlags = MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MIDDLEUP; 2165 | input.mi.dwExtraInfo = 0; 2166 | input.mi.time = 0; 2167 | 2168 | Py_INCREF(Py_None); 2169 | return Py_None; 2170 | } 2171 | 2172 | static PyObject * Input_setMouseMiddleClick(PyObject* self, PyObject* args) 2173 | { 2174 | int x,y; 2175 | 2176 | if( ! PyArg_ParseTuple(args, "ii", &x, &y ) ) 2177 | return NULL; 2178 | 2179 | MousePositionAsPixel( &x, &y ); 2180 | 2181 | ((PyObject_Input*)self)->num = 2; 2182 | 2183 | { 2184 | INPUT & input = ((PyObject_Input*)self)->input[0]; 2185 | input.type = INPUT_MOUSE; 2186 | input.mi.dx = x; 2187 | input.mi.dy = y; 2188 | input.mi.mouseData = 0; 2189 | input.mi.dwFlags = MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MIDDLEDOWN; 2190 | input.mi.dwExtraInfo = 0; 2191 | input.mi.time = 0; 2192 | } 2193 | 2194 | { 2195 | INPUT & input = ((PyObject_Input*)self)->input[1]; 2196 | input.type = INPUT_MOUSE; 2197 | input.mi.dx = x; 2198 | input.mi.dy = y; 2199 | input.mi.mouseData = 0; 2200 | input.mi.dwFlags = MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MIDDLEUP; 2201 | input.mi.dwExtraInfo = 0; 2202 | input.mi.time = 0; 2203 | } 2204 | 2205 | Py_INCREF(Py_None); 2206 | return Py_None; 2207 | } 2208 | 2209 | static PyObject * Input_setMouseWheel(PyObject* self, PyObject* args) 2210 | { 2211 | int x,y; 2212 | float wheel; 2213 | 2214 | if( ! PyArg_ParseTuple(args, "iif", &x, &y, &wheel ) ) 2215 | return NULL; 2216 | 2217 | MousePositionAsPixel( &x, &y ); 2218 | 2219 | ((PyObject_Input*)self)->num = 1; 2220 | 2221 | INPUT & input = ((PyObject_Input*)self)->input[0]; 2222 | input.type = INPUT_MOUSE; 2223 | input.mi.dx = x; 2224 | input.mi.dy = y; 2225 | input.mi.mouseData = (DWORD)(wheel * WHEEL_DELTA); 2226 | input.mi.dwFlags = MOUSEEVENTF_WHEEL | MOUSEEVENTF_ABSOLUTE; 2227 | input.mi.dwExtraInfo = 0; 2228 | input.mi.time = 0; 2229 | 2230 | Py_INCREF(Py_None); 2231 | return Py_None; 2232 | } 2233 | 2234 | static PyObject * Input_setMouseHorizontalWheel(PyObject* self, PyObject* args) 2235 | { 2236 | int x,y; 2237 | float wheel; 2238 | 2239 | if( ! PyArg_ParseTuple(args, "iif", &x, &y, &wheel ) ) 2240 | return NULL; 2241 | 2242 | MousePositionAsPixel( &x, &y ); 2243 | 2244 | ((PyObject_Input*)self)->num = 1; 2245 | 2246 | INPUT & input = ((PyObject_Input*)self)->input[0]; 2247 | input.type = INPUT_MOUSE; 2248 | input.mi.dx = x; 2249 | input.mi.dy = y; 2250 | input.mi.mouseData = (DWORD)(wheel * WHEEL_DELTA); 2251 | input.mi.dwFlags = MOUSEEVENTF_HWHEEL | MOUSEEVENTF_ABSOLUTE; 2252 | input.mi.dwExtraInfo = 0; 2253 | input.mi.time = 0; 2254 | 2255 | Py_INCREF(Py_None); 2256 | return Py_None; 2257 | } 2258 | 2259 | static PyObject * Input_send( PyObject * self, PyObject * args ) 2260 | { 2261 | PyObject * py_input_list; 2262 | 2263 | if( ! PyArg_ParseTuple(args,"O", &py_input_list ) ) 2264 | return NULL; 2265 | 2266 | if( !PyTuple_Check(py_input_list) && !PyList_Check(py_input_list) ) 2267 | { 2268 | PyErr_SetString( PyExc_TypeError, "argument must be a tuple or list." ); 2269 | return NULL; 2270 | } 2271 | 2272 | int item_num = (int)PySequence_Length(py_input_list); 2273 | 2274 | INPUT * input = new INPUT[ item_num * 2 ]; 2275 | int num_input = 0; 2276 | 2277 | for( int i=0 ; inum ; k++ ) 2291 | { 2292 | input[num_input] = ((PyObject_Input*)pyitem)->input[k]; 2293 | 2294 | switch(input[num_input].type) 2295 | { 2296 | case INPUT_MOUSE: 2297 | input[num_input].mi.time = g.last_key_time; 2298 | input[num_input].mi.dwExtraInfo = (ULONG_PTR)g.module_handle; 2299 | break; 2300 | 2301 | case INPUT_KEYBOARD: 2302 | input[num_input].ki.time = g.last_key_time; 2303 | input[num_input].ki.dwExtraInfo = (ULONG_PTR)g.module_handle; 2304 | break; 2305 | } 2306 | 2307 | ++num_input; 2308 | } 2309 | 2310 | Py_XDECREF(pyitem); 2311 | } 2312 | 2313 | UINT num_sent = SendInput( num_input, input, sizeof(INPUT) ); 2314 | 2315 | delete [] input; 2316 | 2317 | if( num_sent != num_input ) 2318 | { 2319 | PyErr_Format( PyExc_WindowsError, "SendInput failed : num_input=%d, num_sent=%d, errno=%d", num_input, num_sent, GetLastError() ); 2320 | return NULL; 2321 | } 2322 | 2323 | Py_INCREF(Py_None); 2324 | return Py_None; 2325 | } 2326 | 2327 | static PyObject * Input_getCursorPos( PyObject * self, PyObject * args ) 2328 | { 2329 | if( ! PyArg_ParseTuple(args,"") ) 2330 | return NULL; 2331 | 2332 | POINT pos; 2333 | GetCursorPos(&pos); 2334 | 2335 | PyObject * pyret = Py_BuildValue( "(ii)", pos.x, pos.y ); 2336 | return pyret; 2337 | } 2338 | 2339 | static PyObject * Input_getKeyboardState( PyObject * self, PyObject * args ) 2340 | { 2341 | if( ! PyArg_ParseTuple(args,"") ) 2342 | return NULL; 2343 | 2344 | BYTE buf[256]; 2345 | if( ! GetKeyboardState(buf) ) 2346 | { 2347 | PyErr_SetFromWindowsErr(0); 2348 | return NULL; 2349 | } 2350 | 2351 | PyObject * pyret = Py_BuildValue( "y#", buf, sizeof(buf) ); 2352 | return pyret; 2353 | } 2354 | 2355 | static PyObject * Input_setKeyboardState( PyObject * self, PyObject * args ) 2356 | { 2357 | BYTE * buf; 2358 | unsigned int bufsize; 2359 | 2360 | if( ! PyArg_ParseTuple( args, "s#", &buf, &bufsize ) ) 2361 | return NULL; 2362 | 2363 | if( ! SetKeyboardState(buf) ) 2364 | { 2365 | PyErr_SetFromWindowsErr(0); 2366 | return NULL; 2367 | } 2368 | 2369 | Py_INCREF(Py_None); 2370 | return Py_None; 2371 | } 2372 | 2373 | static PyObject * Input_getKeyState( PyObject * self, PyObject * args ) 2374 | { 2375 | int vk; 2376 | if( ! PyArg_ParseTuple(args,"i",&vk) ) 2377 | return NULL; 2378 | 2379 | SHORT state = GetKeyState(vk); 2380 | 2381 | PyObject * pyret = Py_BuildValue( "H", (USHORT)state ); 2382 | return pyret; 2383 | } 2384 | 2385 | static PyObject * Input_getAsyncKeyState( PyObject * self, PyObject * args ) 2386 | { 2387 | int vk; 2388 | if( ! PyArg_ParseTuple(args,"i",&vk) ) 2389 | return NULL; 2390 | 2391 | SHORT state = GetAsyncKeyState(vk); 2392 | 2393 | PyObject * pyret = Py_BuildValue( "H", (USHORT)state ); 2394 | return pyret; 2395 | } 2396 | 2397 | static PyMethodDef Input_methods[] = { 2398 | { "setKeyDown", Input_setKeyDown, METH_VARARGS, "" }, 2399 | { "setKeyUp", Input_setKeyUp, METH_VARARGS, "" }, 2400 | { "setKey", Input_setKey, METH_VARARGS, "" }, 2401 | { "setChar", Input_setChar, METH_VARARGS, "" }, 2402 | { "setMouseMove", Input_setMouseMove, METH_VARARGS, "" }, 2403 | { "setMouseLeftDown", Input_setMouseLeftDown, METH_VARARGS, "" }, 2404 | { "setMouseLeftUp", Input_setMouseLeftUp, METH_VARARGS, "" }, 2405 | { "setMouseLeftClick", Input_setMouseLeftClick, METH_VARARGS, "" }, 2406 | { "setMouseRightDown", Input_setMouseRightDown, METH_VARARGS, "" }, 2407 | { "setMouseRightUp", Input_setMouseRightUp, METH_VARARGS, "" }, 2408 | { "setMouseRightClick", Input_setMouseRightClick, METH_VARARGS, "" }, 2409 | { "setMouseMiddleDown", Input_setMouseMiddleDown, METH_VARARGS, "" }, 2410 | { "setMouseMiddleUp", Input_setMouseMiddleUp, METH_VARARGS, "" }, 2411 | { "setMouseMiddleClick", Input_setMouseMiddleClick, METH_VARARGS, "" }, 2412 | { "setMouseWheel", Input_setMouseWheel, METH_VARARGS, "" }, 2413 | { "setMouseHorizontalWheel", Input_setMouseHorizontalWheel, METH_VARARGS, "" }, 2414 | { "send", Input_send, METH_STATIC|METH_VARARGS, "" }, 2415 | { "getCursorPos", Input_getCursorPos, METH_STATIC|METH_VARARGS, "" }, 2416 | { "getKeyboardState", Input_getKeyboardState, METH_STATIC|METH_VARARGS, "" }, 2417 | { "setKeyboardState", Input_setKeyboardState, METH_STATIC|METH_VARARGS, "" }, 2418 | { "getKeyState", Input_getKeyState, METH_STATIC|METH_VARARGS, "" }, 2419 | { "getAsyncKeyState", Input_getAsyncKeyState, METH_STATIC|METH_VARARGS, "" }, 2420 | {NULL,NULL} 2421 | }; 2422 | 2423 | PyTypeObject pyauto::PyType_Input = { 2424 | PyVarObject_HEAD_INIT(NULL, 0) 2425 | "Input", /* tp_name */ 2426 | sizeof(PyType_Input), /* tp_basicsize */ 2427 | 0, /* tp_itemsize */ 2428 | 0, /* tp_dealloc */ 2429 | 0, /* tp_print */ 2430 | 0, /* tp_getattr */ 2431 | 0, /* tp_setattr */ 2432 | 0, /* tp_compare */ 2433 | Input_repr, /* tp_repr */ 2434 | 0, /* tp_as_number */ 2435 | 0, /* tp_as_sequence */ 2436 | 0, /* tp_as_mapping */ 2437 | 0, /* tp_hash */ 2438 | 0, /* tp_call */ 2439 | 0, /* tp_str */ 2440 | PyObject_GenericGetAttr,/* tp_getattro */ 2441 | PyObject_GenericSetAttr,/* tp_setattro */ 2442 | 0, /* tp_as_buffer */ 2443 | Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,/* tp_flags */ 2444 | "", /* tp_doc */ 2445 | 0, /* tp_traverse */ 2446 | 0, /* tp_clear */ 2447 | 0, /* tp_richcompare */ 2448 | 0, /* tp_weaklistoffset */ 2449 | 0, /* tp_iter */ 2450 | 0, /* tp_iternext */ 2451 | Input_methods, /* tp_methods */ 2452 | 0, /* tp_members */ 2453 | 0, /* tp_getset */ 2454 | 0, /* tp_base */ 2455 | 0, /* tp_dict */ 2456 | 0, /* tp_descr_get */ 2457 | 0, /* tp_descr_set */ 2458 | 0, /* tp_dictoffset */ 2459 | Input_init, /* tp_init */ 2460 | 0, /* tp_alloc */ 2461 | PyType_GenericNew, /* tp_new */ 2462 | 0, /* tp_free */ 2463 | }; 2464 | 2465 | // ------------ PyObject_Hook ----------------------------------------- 2466 | 2467 | // フックのフラグを、擬似入力のフラグに変換する 2468 | static int flags_conv( DWORD flags ) 2469 | { 2470 | int ret = 0; 2471 | if( flags & LLKHF_EXTENDED ) ret |= KEYEVENTF_EXTENDEDKEY; 2472 | if( flags & LLKHF_UP ) ret |= KEYEVENTF_KEYUP; 2473 | return ret; 2474 | } 2475 | 2476 | static LRESULT CALLBACK Hook_wndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) 2477 | { 2478 | PythonUtil::GIL_Ensure gil_ensure; 2479 | 2480 | switch(message) 2481 | { 2482 | case WM_CREATE: 2483 | break; 2484 | 2485 | case WM_DESTROY: 2486 | break; 2487 | 2488 | case WM_CLIPBOARDUPDATE: 2489 | return Hook_Clipboard_wndProc(hWnd, message, wParam, lParam ); 2490 | break; 2491 | 2492 | default: 2493 | return DefWindowProc(hWnd, message, wParam, lParam); 2494 | } 2495 | return 0; 2496 | } 2497 | 2498 | static int Hook_init( PyObject * self, PyObject * args, PyObject * kwds) 2499 | { 2500 | if( ! PyArg_ParseTuple( args, "" ) ) 2501 | return -1; 2502 | 2503 | ((PyObject_Hook*)self)->keydown = 0; 2504 | ((PyObject_Hook*)self)->keyup = 0; 2505 | ((PyObject_Hook*)self)->mousedown = 0; 2506 | ((PyObject_Hook*)self)->mouseup = 0; 2507 | ((PyObject_Hook*)self)->mousedblclk = 0; 2508 | ((PyObject_Hook*)self)->mousemove = 0; 2509 | ((PyObject_Hook*)self)->mousewheel = 0; 2510 | ((PyObject_Hook*)self)->mousehorizontalwheel = 0; 2511 | ((PyObject_Hook*)self)->clipboard = 0; 2512 | 2513 | // ウィンドウクラスの登録 2514 | { 2515 | WNDCLASSEX wcex; 2516 | 2517 | wcex.cbSize = sizeof(WNDCLASSEX); 2518 | 2519 | wcex.style = CS_HREDRAW | CS_VREDRAW; 2520 | wcex.lpfnWndProc = (WNDPROC)Hook_wndProc; 2521 | wcex.cbClsExtra = 0; 2522 | wcex.cbWndExtra = 0; 2523 | wcex.hInstance = g.module_handle; 2524 | wcex.hIcon = 0; 2525 | wcex.hCursor = 0; 2526 | wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); 2527 | wcex.lpszMenuName = 0; 2528 | wcex.lpszClassName = _T(PYAUTO_WINDOW_NAME); 2529 | wcex.hIconSm = 0; 2530 | 2531 | RegisterClassEx(&wcex); 2532 | } 2533 | 2534 | // フックのイベントを受け取るためのウィンドウを作成 2535 | g.pyauto_window = CreateWindow( _T(PYAUTO_WINDOW_NAME), _T(PYAUTO_WINDOW_NAME), WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, g.module_handle, NULL ); 2536 | 2537 | // Hookオブジェクトを記録する 2538 | g.pyhook = (PyObject_Hook*)self; 2539 | 2540 | return 0; 2541 | } 2542 | 2543 | static void _Hook_destroy() 2544 | { 2545 | if(g.pyhook) 2546 | { 2547 | HookEnd_Key(); 2548 | HookEnd_Clipboard(); 2549 | 2550 | DestroyWindow(g.pyauto_window); 2551 | g.pyauto_window = NULL; 2552 | 2553 | g.pyhook = NULL; 2554 | } 2555 | } 2556 | 2557 | static void Hook_dealloc( PyObject * self ) 2558 | { 2559 | _Hook_destroy(); 2560 | 2561 | Py_XDECREF(((PyObject_Hook*)self)->keydown); 2562 | Py_XDECREF(((PyObject_Hook*)self)->keyup); 2563 | Py_XDECREF(((PyObject_Hook*)self)->mousedown); 2564 | Py_XDECREF(((PyObject_Hook*)self)->mouseup); 2565 | Py_XDECREF(((PyObject_Hook*)self)->mousedblclk); 2566 | Py_XDECREF(((PyObject_Hook*)self)->mousemove); 2567 | Py_XDECREF(((PyObject_Hook*)self)->mousewheel); 2568 | Py_XDECREF(((PyObject_Hook*)self)->mousehorizontalwheel); 2569 | Py_XDECREF(((PyObject_Hook*)self)->clipboard); 2570 | 2571 | self->ob_type->tp_free((PyObject*)self); 2572 | } 2573 | 2574 | static PyObject * Hook_destroy( PyObject* self, PyObject* args ) 2575 | { 2576 | if( ! PyArg_ParseTuple(args, "" ) ) 2577 | return NULL; 2578 | 2579 | _Hook_destroy(); 2580 | 2581 | Py_INCREF(Py_None); 2582 | return Py_None; 2583 | } 2584 | 2585 | static PyObject * Hook_getattr( PyObject_Hook * self, PyObject * pyattrname ) 2586 | { 2587 | Py_ssize_t len; 2588 | const wchar_t* attrname = PyUnicode_AsWideCharString(pyattrname, &len); 2589 | 2590 | if( attrname[0]=='k' && wcscmp(attrname,L"keydown")==0 ) 2591 | { 2592 | if(self->keydown) 2593 | { 2594 | Py_INCREF(self->keydown); 2595 | return self->keydown; 2596 | } 2597 | else 2598 | { 2599 | Py_INCREF(Py_None); 2600 | return Py_None; 2601 | } 2602 | } 2603 | else if( attrname[0]=='k' && wcscmp(attrname,L"keyup")==0 ) 2604 | { 2605 | if(self->keyup) 2606 | { 2607 | Py_INCREF(self->keyup); 2608 | return self->keyup; 2609 | } 2610 | else 2611 | { 2612 | Py_INCREF(Py_None); 2613 | return Py_None; 2614 | } 2615 | } 2616 | else if( attrname[0]=='m' && wcscmp(attrname,L"mousedown")==0 ) 2617 | { 2618 | if(self->mousedown) 2619 | { 2620 | Py_INCREF(self->mousedown); 2621 | return self->mousedown; 2622 | } 2623 | else 2624 | { 2625 | Py_INCREF(Py_None); 2626 | return Py_None; 2627 | } 2628 | } 2629 | else if( attrname[0]=='m' && wcscmp(attrname,L"mouseup")==0 ) 2630 | { 2631 | if(self->mouseup) 2632 | { 2633 | Py_INCREF(self->mouseup); 2634 | return self->mouseup; 2635 | } 2636 | else 2637 | { 2638 | Py_INCREF(Py_None); 2639 | return Py_None; 2640 | } 2641 | } 2642 | else if( attrname[0]=='m' && wcscmp(attrname,L"mousedblclk")==0 ) 2643 | { 2644 | if(self->mousedblclk) 2645 | { 2646 | Py_INCREF(self->mousedblclk); 2647 | return self->mousedblclk; 2648 | } 2649 | else 2650 | { 2651 | Py_INCREF(Py_None); 2652 | return Py_None; 2653 | } 2654 | } 2655 | else if( attrname[0]=='m' && wcscmp(attrname,L"mousemove")==0 ) 2656 | { 2657 | if(self->mousemove) 2658 | { 2659 | Py_INCREF(self->mousemove); 2660 | return self->mousemove; 2661 | } 2662 | else 2663 | { 2664 | Py_INCREF(Py_None); 2665 | return Py_None; 2666 | } 2667 | } 2668 | else if( attrname[0]=='m' && wcscmp(attrname,L"mousewheel")==0 ) 2669 | { 2670 | if(self->mousewheel) 2671 | { 2672 | Py_INCREF(self->mousewheel); 2673 | return self->mousewheel; 2674 | } 2675 | else 2676 | { 2677 | Py_INCREF(Py_None); 2678 | return Py_None; 2679 | } 2680 | } 2681 | else if( attrname[0]=='m' && wcscmp(attrname,L"mousehorizontalwheel")==0 ) 2682 | { 2683 | if(self->mousehorizontalwheel) 2684 | { 2685 | Py_INCREF(self->mousehorizontalwheel); 2686 | return self->mousehorizontalwheel; 2687 | } 2688 | else 2689 | { 2690 | Py_INCREF(Py_None); 2691 | return Py_None; 2692 | } 2693 | } 2694 | else if( attrname[0]=='c' && wcscmp(attrname,L"clipboard")==0 ) 2695 | { 2696 | if(self->clipboard) 2697 | { 2698 | Py_INCREF(self->clipboard); 2699 | return self->clipboard; 2700 | } 2701 | else 2702 | { 2703 | Py_INCREF(Py_None); 2704 | return Py_None; 2705 | } 2706 | } 2707 | else 2708 | { 2709 | return PyObject_GenericGetAttr((PyObject*)self,pyattrname); 2710 | } 2711 | } 2712 | 2713 | static int Hook_setattr( PyObject_Hook * self, PyObject * pyattrname, PyObject * pyvalue ) 2714 | { 2715 | Py_ssize_t len; 2716 | const wchar_t* attrname = PyUnicode_AsWideCharString(pyattrname, &len); 2717 | 2718 | if( attrname[0]=='k' && wcscmp(attrname,L"keydown")==0 ) 2719 | { 2720 | if(pyvalue!=Py_None) 2721 | { 2722 | Py_INCREF(pyvalue); 2723 | Py_XDECREF(self->keydown); 2724 | self->keydown = pyvalue; 2725 | 2726 | HookStart_Key(); 2727 | } 2728 | else 2729 | { 2730 | Py_XDECREF(self->keydown); 2731 | self->keydown = NULL; 2732 | } 2733 | } 2734 | else if( attrname[0]=='k' && wcscmp(attrname,L"keyup")==0 ) 2735 | { 2736 | if(pyvalue!=Py_None) 2737 | { 2738 | Py_INCREF(pyvalue); 2739 | Py_XDECREF(self->keyup); 2740 | self->keyup = pyvalue; 2741 | 2742 | HookStart_Key(); 2743 | } 2744 | else 2745 | { 2746 | Py_XDECREF(self->keyup); 2747 | self->keyup = NULL; 2748 | } 2749 | } 2750 | else if( attrname[0]=='m' && wcscmp(attrname,L"mousedown")==0 ) 2751 | { 2752 | if(pyvalue!=Py_None) 2753 | { 2754 | Py_INCREF(pyvalue); 2755 | Py_XDECREF(self->mousedown); 2756 | self->mousedown = pyvalue; 2757 | 2758 | HookStart_Mouse(); 2759 | } 2760 | else 2761 | { 2762 | Py_XDECREF(self->mousedown); 2763 | self->mousedown = NULL; 2764 | } 2765 | } 2766 | else if( attrname[0]=='m' && wcscmp(attrname,L"mouseup")==0 ) 2767 | { 2768 | if(pyvalue!=Py_None) 2769 | { 2770 | Py_INCREF(pyvalue); 2771 | Py_XDECREF(self->mouseup); 2772 | self->mouseup = pyvalue; 2773 | 2774 | HookStart_Mouse(); 2775 | } 2776 | else 2777 | { 2778 | Py_XDECREF(self->mouseup); 2779 | self->mouseup = NULL; 2780 | } 2781 | } 2782 | else if( attrname[0]=='m' && wcscmp(attrname,L"mousedblclk")==0 ) 2783 | { 2784 | if(pyvalue!=Py_None) 2785 | { 2786 | Py_INCREF(pyvalue); 2787 | Py_XDECREF(self->mousedblclk); 2788 | self->mousedblclk = pyvalue; 2789 | 2790 | HookStart_Mouse(); 2791 | } 2792 | else 2793 | { 2794 | Py_XDECREF(self->mousedblclk); 2795 | self->mousedblclk = NULL; 2796 | } 2797 | } 2798 | else if( attrname[0]=='m' && wcscmp(attrname,L"mousemove")==0 ) 2799 | { 2800 | if(pyvalue!=Py_None) 2801 | { 2802 | Py_INCREF(pyvalue); 2803 | Py_XDECREF(self->mousemove); 2804 | self->mousemove = pyvalue; 2805 | 2806 | HookStart_Mouse(); 2807 | } 2808 | else 2809 | { 2810 | Py_XDECREF(self->mousemove); 2811 | self->mousemove = NULL; 2812 | } 2813 | } 2814 | else if( attrname[0]=='m' && wcscmp(attrname,L"mousewheel")==0 ) 2815 | { 2816 | if(pyvalue!=Py_None) 2817 | { 2818 | Py_INCREF(pyvalue); 2819 | Py_XDECREF(self->mousewheel); 2820 | self->mousewheel = pyvalue; 2821 | 2822 | HookStart_Mouse(); 2823 | } 2824 | else 2825 | { 2826 | Py_XDECREF(self->mousewheel); 2827 | self->mousewheel = NULL; 2828 | } 2829 | } 2830 | else if( attrname[0]=='m' && wcscmp(attrname,L"mousehorizontalwheel")==0 ) 2831 | { 2832 | if(pyvalue!=Py_None) 2833 | { 2834 | Py_INCREF(pyvalue); 2835 | Py_XDECREF(self->mousehorizontalwheel); 2836 | self->mousehorizontalwheel = pyvalue; 2837 | 2838 | HookStart_Mouse(); 2839 | } 2840 | else 2841 | { 2842 | Py_XDECREF(self->mousehorizontalwheel); 2843 | self->mousehorizontalwheel = NULL; 2844 | } 2845 | } 2846 | else if( attrname[0]=='c' && wcscmp(attrname,L"clipboard")==0 ) 2847 | { 2848 | if(pyvalue!=Py_None) 2849 | { 2850 | Py_INCREF(pyvalue); 2851 | Py_XDECREF(self->clipboard); 2852 | self->clipboard = pyvalue; 2853 | 2854 | HookStart_Clipboard(); 2855 | } 2856 | else 2857 | { 2858 | Py_XDECREF(self->clipboard); 2859 | self->clipboard = NULL; 2860 | 2861 | HookEnd_Clipboard(); 2862 | } 2863 | } 2864 | else 2865 | { 2866 | return PyObject_GenericSetAttr((PyObject*)self,pyattrname,pyvalue); 2867 | } 2868 | 2869 | return 0; 2870 | } 2871 | 2872 | static PyObject * Hook_reset( PyObject_Hook * self, PyObject* args ) 2873 | { 2874 | if( ! PyArg_ParseTuple(args, "" ) ) 2875 | return NULL; 2876 | 2877 | // フック解除 2878 | { 2879 | PythonUtil_DebugPrintf("unset hook\n"); 2880 | 2881 | HookEnd_Key(); 2882 | HookEnd_Mouse(); 2883 | HookEnd_Clipboard(); 2884 | } 2885 | 2886 | // フック再スタート 2887 | { 2888 | PythonUtil_DebugPrintf("set hook\n"); 2889 | 2890 | if( self->keydown || self->keyup ) 2891 | { 2892 | HookStart_Key(); 2893 | } 2894 | 2895 | if( self->mousedown || self->mouseup || self->mousedblclk || self->mousemove || self->mousewheel || self->mousehorizontalwheel ) 2896 | { 2897 | HookStart_Mouse(); 2898 | } 2899 | 2900 | HookStart_Clipboard(); 2901 | } 2902 | 2903 | Py_INCREF(Py_None); 2904 | return Py_None; 2905 | } 2906 | 2907 | static PyMethodDef Hook_methods[] = { 2908 | { "destroy", Hook_destroy, METH_VARARGS, "" }, 2909 | { "reset", (PyCFunction)Hook_reset, METH_VARARGS, "" }, 2910 | {NULL,NULL} 2911 | }; 2912 | 2913 | PyTypeObject pyauto::PyType_Hook = { 2914 | PyVarObject_HEAD_INIT(NULL, 0) 2915 | "Hook", /* tp_name */ 2916 | sizeof(PyType_Hook), /* tp_basicsize */ 2917 | 0, /* tp_itemsize */ 2918 | Hook_dealloc, /* tp_dealloc */ 2919 | 0, /* tp_print */ 2920 | 0, /* tp_getattr */ 2921 | 0, /* tp_setattr */ 2922 | 0, /* tp_compare */ 2923 | 0, /* tp_repr */ 2924 | 0, /* tp_as_number */ 2925 | 0, /* tp_as_sequence */ 2926 | 0, /* tp_as_mapping */ 2927 | 0, /* tp_hash */ 2928 | 0, /* tp_call */ 2929 | 0, /* tp_str */ 2930 | (getattrofunc)Hook_getattr, /* tp_getattro */ 2931 | (setattrofunc)Hook_setattr, /* tp_setattro */ 2932 | 0, /* tp_as_buffer */ 2933 | Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,/* tp_flags */ 2934 | "", /* tp_doc */ 2935 | 0, /* tp_traverse */ 2936 | 0, /* tp_clear */ 2937 | 0, /* tp_richcompare */ 2938 | 0, /* tp_weaklistoffset */ 2939 | 0, /* tp_iter */ 2940 | 0, /* tp_iternext */ 2941 | Hook_methods, /* tp_methods */ 2942 | 0, /* tp_members */ 2943 | 0, /* tp_getset */ 2944 | 0, /* tp_base */ 2945 | 0, /* tp_dict */ 2946 | 0, /* tp_descr_get */ 2947 | 0, /* tp_descr_set */ 2948 | 0, /* tp_dictoffset */ 2949 | Hook_init, /* tp_init */ 2950 | 0, /* tp_alloc */ 2951 | PyType_GenericNew, /* tp_new */ 2952 | 0, /* tp_free */ 2953 | }; 2954 | 2955 | // ------------ global function ----------------------------------------- 2956 | 2957 | static PyObject * _shellExecute( PyObject * self, PyObject * args ) 2958 | { 2959 | BOOL result; 2960 | PyObject * pyverb; 2961 | PyObject * pyfile; 2962 | PyObject * pyparam=NULL; 2963 | PyObject * pydirectory=NULL; 2964 | PyObject * pyswmode=NULL; 2965 | 2966 | if( ! PyArg_ParseTuple(args,"OO|OOO", &pyverb, &pyfile, &pyparam, &pydirectory, &pyswmode ) ) 2967 | return NULL; 2968 | 2969 | const TCHAR * p_file = NULL; 2970 | const TCHAR * p_verb = NULL; 2971 | const TCHAR * p_param = NULL; 2972 | const TCHAR * p_directory = NULL; 2973 | const TCHAR * p_swmode = NULL; 2974 | 2975 | _tString verb; 2976 | _tString file; 2977 | _tString param; 2978 | _tString directory; 2979 | _tString swmode; 2980 | 2981 | if( stringutil::PyStringTo_tString( pyverb, &verb ) ) 2982 | p_verb = verb.c_str(); 2983 | 2984 | if( stringutil::PyStringTo_tString( pyfile, &file ) ) 2985 | p_file = file.c_str(); 2986 | 2987 | if( pyparam && stringutil::PyStringTo_tString( pyparam, ¶m ) ) 2988 | p_param = param.c_str(); 2989 | 2990 | if( pydirectory && stringutil::PyStringTo_tString( pydirectory, &directory ) ) 2991 | p_directory = directory.c_str(); 2992 | 2993 | if( pyswmode && stringutil::PyStringTo_tString( pyswmode, &swmode ) ) 2994 | p_swmode = swmode.c_str(); 2995 | 2996 | SHELLEXECUTEINFO sei; 2997 | ZeroMemory(&sei, sizeof(SHELLEXECUTEINFO)); 2998 | sei.cbSize = sizeof(SHELLEXECUTEINFO); 2999 | sei.fMask = SEE_MASK_INVOKEIDLIST | SEE_MASK_FLAG_NO_UI; 3000 | sei.hwnd = NULL; 3001 | sei.lpVerb = p_verb; 3002 | sei.lpFile = p_file; 3003 | sei.lpParameters = p_param; 3004 | sei.lpDirectory = p_directory; 3005 | 3006 | if( p_swmode==NULL || swmode==_T("") || swmode==_T("normal") ) 3007 | { 3008 | sei.nShow = SW_SHOWNORMAL; 3009 | } 3010 | else if(swmode==_T("minimized")) 3011 | { 3012 | sei.nShow = SW_SHOWMINIMIZED; 3013 | } 3014 | else if(swmode==_T("maximized")) 3015 | { 3016 | sei.nShow = SW_SHOWMAXIMIZED; 3017 | } 3018 | else 3019 | { 3020 | PyErr_SetString( PyExc_ValueError, "invalid show mode." ); 3021 | return NULL; 3022 | } 3023 | 3024 | Py_BEGIN_ALLOW_THREADS 3025 | result = ShellExecuteEx(&sei); 3026 | Py_END_ALLOW_THREADS 3027 | 3028 | if(result) 3029 | { 3030 | Py_INCREF(Py_None); 3031 | return Py_None; 3032 | } 3033 | else 3034 | { 3035 | PyErr_SetFromWindowsErr(0); 3036 | return NULL; 3037 | } 3038 | } 3039 | 3040 | static PyObject * _messageLoop( PyObject * self, PyObject * args ) 3041 | { 3042 | if( ! PyArg_ParseTuple( args, "" ) ) 3043 | return NULL; 3044 | 3045 | MSG msg; 3046 | for(;;) 3047 | { 3048 | while(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) 3049 | { 3050 | if(msg.message == WM_QUIT) 3051 | { 3052 | goto end; 3053 | } 3054 | 3055 | TranslateMessage(&msg); 3056 | DispatchMessage(&msg); 3057 | } 3058 | 3059 | Py_BEGIN_ALLOW_THREADS 3060 | 3061 | WaitMessage(); 3062 | 3063 | Py_END_ALLOW_THREADS 3064 | } 3065 | 3066 | end: 3067 | 3068 | Py_INCREF(Py_None); 3069 | return Py_None; 3070 | } 3071 | 3072 | static PyObject * _setDebug( PyObject * self, PyObject * args ) 3073 | { 3074 | int enabled; 3075 | 3076 | if( ! PyArg_ParseTuple( args, "i", &enabled ) ) 3077 | return NULL; 3078 | 3079 | g.debug = enabled!=0; 3080 | 3081 | Py_INCREF(Py_None); 3082 | return Py_None; 3083 | } 3084 | 3085 | static PyMethodDef pyauto_funcs[] = { 3086 | { "shellExecute", _shellExecute, METH_VARARGS, "" }, 3087 | { "messageLoop", _messageLoop, METH_VARARGS, "" }, 3088 | { "setDebug", _setDebug, METH_VARARGS, "" }, 3089 | {NULL, NULL, 0, NULL} 3090 | }; 3091 | 3092 | // ------------ module init ----------------------------------------- 3093 | 3094 | static PyModuleDef pyautocore_module = 3095 | { 3096 | PyModuleDef_HEAD_INIT, 3097 | MODULE_NAME, 3098 | "pyautocore module.", 3099 | -1, 3100 | pyauto_funcs, 3101 | NULL, NULL, NULL, NULL 3102 | }; 3103 | 3104 | PyMODINIT_FUNC PyInit_pyautocore() 3105 | { 3106 | if( PyType_Ready(&PyType_Window)<0 ) return NULL; 3107 | if( PyType_Ready(&PyType_Image)<0 ) return NULL; 3108 | if( PyType_Ready(&PyType_Input)<0 ) return NULL; 3109 | if( PyType_Ready(&PyType_Hook)<0 ) return NULL; 3110 | 3111 | PyObject *m; 3112 | 3113 | m = PyModule_Create(&pyautocore_module); 3114 | if(m == NULL) return NULL; 3115 | 3116 | Py_INCREF(&PyType_Window); 3117 | PyModule_AddObject( m, "Window", (PyObject*)&PyType_Window ); 3118 | 3119 | Py_INCREF(&PyType_Image); 3120 | PyModule_AddObject( m, "Image", (PyObject*)&PyType_Image ); 3121 | 3122 | Py_INCREF(&PyType_Input); 3123 | PyModule_AddObject( m, "Input", (PyObject*)&PyType_Input ); 3124 | 3125 | Py_INCREF(&PyType_Hook); 3126 | PyModule_AddObject( m, "Hook", (PyObject*)&PyType_Hook ); 3127 | 3128 | g.Error = PyErr_NewException( MODULE_NAME".Error", NULL, NULL); 3129 | Py_INCREF(g.Error); 3130 | PyModule_AddObject( m, "Error", (PyObject*)g.Error ); 3131 | 3132 | if( PyErr_Occurred() ) 3133 | { 3134 | Py_FatalError( "can't initialize module " MODULE_NAME ); 3135 | } 3136 | 3137 | return m; 3138 | } 3139 | 3140 | // ------------ DllMain ----------------------------------------- 3141 | 3142 | BOOL APIENTRY DllMain( HANDLE hModule, 3143 | DWORD ul_reason_for_call, 3144 | LPVOID lpReserved 3145 | ) 3146 | { 3147 | (void)lpReserved; 3148 | if(ul_reason_for_call==DLL_PROCESS_ATTACH) 3149 | { 3150 | g.module_handle = (HMODULE)hModule; 3151 | } 3152 | return TRUE; 3153 | } 3154 | 3155 | --------------------------------------------------------------------------------