gomyck-tools 1.3.1__py3-none-any.whl → 1.3.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- ctools/__init__.py +0 -0
- ctools/aes_tools.py +35 -0
- ctools/api_result.py +55 -0
- ctools/application.py +386 -0
- ctools/b64.py +7 -0
- ctools/bashPath.py +13 -0
- ctools/bottle_web_base.py +169 -0
- ctools/bottle_webserver.py +143 -0
- ctools/bottle_websocket.py +75 -0
- ctools/browser_element_tools.py +314 -0
- ctools/call.py +71 -0
- ctools/cftp.py +74 -0
- ctools/cjson.py +54 -0
- ctools/ckafka.py +159 -0
- ctools/compile_tools.py +18 -0
- ctools/console.py +55 -0
- ctools/coord_trans.py +127 -0
- ctools/credis.py +111 -0
- ctools/cron_lite.py +252 -0
- ctools/ctoken.py +34 -0
- ctools/cword.py +30 -0
- ctools/czip.py +130 -0
- ctools/database.py +185 -0
- ctools/date_utils.py +43 -0
- ctools/dict_wrapper.py +20 -0
- ctools/douglas_rarefy.py +136 -0
- ctools/download_tools.py +57 -0
- ctools/enums.py +4 -0
- ctools/ex.py +31 -0
- ctools/excelOpt.py +36 -0
- ctools/html_soup.py +35 -0
- ctools/http_utils.py +24 -0
- ctools/images_tools.py +27 -0
- ctools/imgDialog.py +44 -0
- ctools/metrics.py +131 -0
- ctools/mqtt_utils.py +289 -0
- ctools/obj.py +20 -0
- ctools/pacth.py +74 -0
- ctools/plan_area_tools.py +97 -0
- ctools/process_pool.py +36 -0
- ctools/pty_tools.py +72 -0
- ctools/resource_bundle_tools.py +121 -0
- ctools/rsa.py +70 -0
- ctools/screenshot_tools.py +127 -0
- ctools/sign.py +20 -0
- ctools/sm_tools.py +49 -0
- ctools/snow_id.py +76 -0
- ctools/str_diff.py +20 -0
- ctools/string_tools.py +85 -0
- ctools/sys_info.py +157 -0
- ctools/sys_log.py +89 -0
- ctools/thread_pool.py +35 -0
- ctools/upload_tools.py +40 -0
- ctools/win_canvas.py +83 -0
- ctools/win_control.py +106 -0
- ctools/word_fill.py +562 -0
- ctools/word_fill_entity.py +46 -0
- ctools/work_path.py +69 -0
- {gomyck_tools-1.3.1.dist-info → gomyck_tools-1.3.2.dist-info}/METADATA +1 -1
- gomyck_tools-1.3.2.dist-info/RECORD +62 -0
- gomyck_tools-1.3.2.dist-info/top_level.txt +1 -0
- gomyck_tools-1.3.1.dist-info/RECORD +0 -4
- gomyck_tools-1.3.1.dist-info/top_level.txt +0 -1
- {gomyck_tools-1.3.1.dist-info → gomyck_tools-1.3.2.dist-info}/WHEEL +0 -0
ctools/sys_info.py
ADDED
@@ -0,0 +1,157 @@
|
|
1
|
+
import hashlib
|
2
|
+
import os
|
3
|
+
import platform
|
4
|
+
|
5
|
+
from ctools import cjson, sm_tools, work_path
|
6
|
+
|
7
|
+
MACHINE_KEY = b'EnrGffoorbFyTYoS0902YyT1Fhehj4InpbezIDUuPOg='
|
8
|
+
|
9
|
+
class MachineInfo:
|
10
|
+
machine_code = None
|
11
|
+
|
12
|
+
def get_user():
|
13
|
+
import getpass
|
14
|
+
return getpass.getuser()
|
15
|
+
|
16
|
+
def get_machine_code():
|
17
|
+
if MachineInfo.machine_code: return MachineInfo.machine_code
|
18
|
+
destPath = os.path.join(work_path.get_user_work_path(), "AppData/Local/machine")
|
19
|
+
machine_file = os.path.join(destPath, 'machine_code.mc')
|
20
|
+
origin_machine_code = get_origin_machine_code()
|
21
|
+
if os.path.exists(machine_file):
|
22
|
+
with open(machine_file, 'r') as f:
|
23
|
+
file_code = f.readline()
|
24
|
+
dec_code = ''
|
25
|
+
try:
|
26
|
+
dec_code = cjson.loads(sm_tools.decrypt_with_sm4(MACHINE_KEY, file_code))
|
27
|
+
origin_code = dec_code.get("origin_code")
|
28
|
+
if origin_code == origin_machine_code:
|
29
|
+
MachineInfo.machine_code = dec_code.get("hash_code")
|
30
|
+
print("use current machine code {}".format(MachineInfo.machine_code))
|
31
|
+
return MachineInfo.machine_code
|
32
|
+
except Exception:
|
33
|
+
print('machine code file is error: {} {}'.format(file_code, dec_code))
|
34
|
+
hash_machine_code = get_hash_machine_code(origin_machine_code)
|
35
|
+
machine_code = {"origin_code": origin_machine_code, "hash_code": hash_machine_code}
|
36
|
+
enc_code = sm_tools.encrypt_with_sm4(MACHINE_KEY, cjson.dumps(machine_code))
|
37
|
+
os.makedirs(destPath, exist_ok=True)
|
38
|
+
with open(machine_file, 'w') as f:
|
39
|
+
f.write(enc_code)
|
40
|
+
f.flush()
|
41
|
+
MachineInfo.machine_code = hash_machine_code
|
42
|
+
print("init new machine code {}".format(hash_machine_code))
|
43
|
+
return MachineInfo.machine_code
|
44
|
+
|
45
|
+
|
46
|
+
def get_origin_machine_code():
|
47
|
+
# 获取CPU序列号
|
48
|
+
cpu_serial = platform.processor()
|
49
|
+
# 获取硬盘序列号
|
50
|
+
disk_serial = ''
|
51
|
+
if platform.system() == 'Windows':
|
52
|
+
import ctypes
|
53
|
+
kernel32 = ctypes.windll.kernel32
|
54
|
+
volume_serial = ctypes.c_ulonglong(0)
|
55
|
+
kernel32.GetVolumeInformationW(
|
56
|
+
ctypes.c_wchar_p("C:\\"),
|
57
|
+
None,
|
58
|
+
0,
|
59
|
+
ctypes.pointer(volume_serial),
|
60
|
+
None,
|
61
|
+
None,
|
62
|
+
None,
|
63
|
+
0
|
64
|
+
)
|
65
|
+
disk_serial = str(volume_serial.value)
|
66
|
+
combined_info = cpu_serial + disk_serial + '-gomyck'
|
67
|
+
return hashlib.md5(combined_info.encode()).hexdigest()
|
68
|
+
|
69
|
+
|
70
|
+
def get_hash_machine_code(origin_code):
|
71
|
+
import uuid
|
72
|
+
code = origin_code + uuid.uuid1().hex
|
73
|
+
machine_code = hashlib.md5(code.encode()).hexdigest()
|
74
|
+
return machine_code.upper()
|
75
|
+
|
76
|
+
def get_public_ip():
|
77
|
+
import requests
|
78
|
+
try:
|
79
|
+
response = requests.get("https://api.ipify.org?format=json")
|
80
|
+
ip = response.json()["ip"]
|
81
|
+
return ip
|
82
|
+
except Exception as e:
|
83
|
+
return f"Failed to get public IP: {e}"
|
84
|
+
|
85
|
+
def get_local_ipv4():
|
86
|
+
import psutil
|
87
|
+
import socket
|
88
|
+
interfaces = psutil.net_if_addrs()
|
89
|
+
for interface, addresses in interfaces.items():
|
90
|
+
for address in addresses:
|
91
|
+
if address.family == socket.AF_INET and not address.address.startswith("127."):
|
92
|
+
return address.address
|
93
|
+
print("Failed to get local IPv4 address, try another way...")
|
94
|
+
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
95
|
+
try:
|
96
|
+
s.connect(("8.8.8.8", 80))
|
97
|
+
ip = s.getsockname()[0]
|
98
|
+
except Exception:
|
99
|
+
ip = '127.0.0.1'
|
100
|
+
finally:
|
101
|
+
s.close()
|
102
|
+
return ip
|
103
|
+
|
104
|
+
def get_remote_ipv4():
|
105
|
+
from bottle import request
|
106
|
+
try:
|
107
|
+
return request.remote_route[0]
|
108
|
+
except:
|
109
|
+
return '127.0.0.1'
|
110
|
+
|
111
|
+
def get_proc_pid_by(cmdline):
|
112
|
+
import psutil
|
113
|
+
"""
|
114
|
+
根据命令行信息获取进程pid
|
115
|
+
:param cmdline:
|
116
|
+
:return:
|
117
|
+
"""
|
118
|
+
pid_list = []
|
119
|
+
proc_list = psutil.process_iter()
|
120
|
+
for proc in proc_list:
|
121
|
+
try:
|
122
|
+
cmdline_str = "".join(proc.cmdline())
|
123
|
+
if cmdline in cmdline_str:
|
124
|
+
pid_list.append(proc.pid)
|
125
|
+
except Exception:
|
126
|
+
pass
|
127
|
+
return pid_list
|
128
|
+
|
129
|
+
def get_os_architecture():
|
130
|
+
if '64' in platform.machine():
|
131
|
+
return '64'
|
132
|
+
else:
|
133
|
+
return '32'
|
134
|
+
|
135
|
+
|
136
|
+
def get_os_architecture4x():
|
137
|
+
if '64' in platform.machine():
|
138
|
+
return 'x64'
|
139
|
+
else:
|
140
|
+
return 'x86'
|
141
|
+
|
142
|
+
|
143
|
+
def get_os_version():
|
144
|
+
system = platform.system()
|
145
|
+
if system == "Windows":
|
146
|
+
version = platform.win32_ver()[0]
|
147
|
+
return version
|
148
|
+
else:
|
149
|
+
return "Unsupported OS"
|
150
|
+
|
151
|
+
|
152
|
+
def get_platform_name():
|
153
|
+
version = get_os_version()
|
154
|
+
if version == '7':
|
155
|
+
return 'win{}{}'.format(version, get_os_architecture4x())
|
156
|
+
else:
|
157
|
+
return 'win{}'.format(version)
|
ctools/sys_log.py
ADDED
@@ -0,0 +1,89 @@
|
|
1
|
+
import logging
|
2
|
+
import os
|
3
|
+
import sys
|
4
|
+
import time
|
5
|
+
import traceback
|
6
|
+
|
7
|
+
from ctools import call, work_path
|
8
|
+
|
9
|
+
clog: logging.Logger = None
|
10
|
+
flog: logging.Logger = None
|
11
|
+
|
12
|
+
neglect_keywords = [
|
13
|
+
"OPTIONS",
|
14
|
+
]
|
15
|
+
|
16
|
+
|
17
|
+
# 文件日志
|
18
|
+
@call.once
|
19
|
+
def _file_log(sys_log_path: str = './', log_level: int = logging.INFO, mixin: bool = False) -> logging:
|
20
|
+
try:
|
21
|
+
os.mkdir(sys_log_path)
|
22
|
+
except Exception:
|
23
|
+
pass
|
24
|
+
log_file = sys_log_path + os.path.sep + "log-" + time.strftime("%Y-%m-%d-%H", time.localtime(time.time())) + ".log"
|
25
|
+
if mixin:
|
26
|
+
handlers = [logging.FileHandler(filename=log_file, encoding='utf-8'), logging.StreamHandler()]
|
27
|
+
else:
|
28
|
+
handlers = [logging.FileHandler(filename=log_file, encoding='utf-8')]
|
29
|
+
logging.basicConfig(level=log_level,
|
30
|
+
format='%(asctime)s-%(levelname)s-%(thread)d-%(module)s(%(funcName)s:%(lineno)d) %(message)s',
|
31
|
+
datefmt='%Y%m%d%H%M%S',
|
32
|
+
handlers=handlers)
|
33
|
+
logger = logging.getLogger('ck-flog')
|
34
|
+
return logger
|
35
|
+
|
36
|
+
|
37
|
+
# 控制台日志
|
38
|
+
@call.once
|
39
|
+
def _console_log(log_level: int = logging.INFO) -> logging:
|
40
|
+
handler = logging.StreamHandler()
|
41
|
+
logging.basicConfig(level=log_level,
|
42
|
+
format='%(asctime)s-%(levelname)s-%(thread)d-%(module)s(%(funcName)s:%(lineno)d) %(message)s',
|
43
|
+
datefmt='%Y%m%d%H%M%S',
|
44
|
+
handlers=[handler])
|
45
|
+
logger = logging.getLogger('ck-clog')
|
46
|
+
return logger
|
47
|
+
|
48
|
+
|
49
|
+
class GlobalLogger(object):
|
50
|
+
def __init__(self, logger):
|
51
|
+
sys.stdout = self
|
52
|
+
sys.stderr = self
|
53
|
+
sys.excepthook = self.handle_exception
|
54
|
+
self.log = logger
|
55
|
+
|
56
|
+
def write(self, message):
|
57
|
+
if message == '\n' or message == '\r\n': return
|
58
|
+
global neglect_keywords
|
59
|
+
for neglect_keyword in neglect_keywords:
|
60
|
+
if neglect_keyword in message: return
|
61
|
+
try:
|
62
|
+
stack = traceback.extract_stack(limit=3)
|
63
|
+
caller = stack[-2]
|
64
|
+
location = f"{os.path.splitext(os.path.basename(caller.filename))[0]}({caller.name}:{caller.lineno})"
|
65
|
+
self.log.info(f"{location} {message.strip()}")
|
66
|
+
except Exception:
|
67
|
+
self.log.info(message.strip())
|
68
|
+
|
69
|
+
def handle_exception(self, exc_type, exc_value, exc_traceback):
|
70
|
+
if issubclass(exc_type, KeyboardInterrupt):
|
71
|
+
sys.__excepthook__(exc_type, exc_value, exc_traceback)
|
72
|
+
return
|
73
|
+
formatted_exception = ''.join(traceback.format_exception(exc_type, exc_value, exc_traceback))
|
74
|
+
self.log.error(f"An error occurred:\n{formatted_exception.strip()}")
|
75
|
+
|
76
|
+
def flush(self):
|
77
|
+
pass
|
78
|
+
|
79
|
+
|
80
|
+
@call.init
|
81
|
+
def _init_log() -> None:
|
82
|
+
global flog, clog
|
83
|
+
flog = _file_log(sys_log_path='{}/ck-py-log/'.format(work_path.get_user_work_path()), mixin=True, log_level=logging.DEBUG)
|
84
|
+
clog = _console_log()
|
85
|
+
GlobalLogger(flog)
|
86
|
+
|
87
|
+
def setLevel(log_level=logging.INFO):
|
88
|
+
flog.setLevel(log_level)
|
89
|
+
clog.setLevel(log_level)
|
ctools/thread_pool.py
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
import os
|
2
|
+
import threading
|
3
|
+
import time
|
4
|
+
from concurrent.futures import ThreadPoolExecutor
|
5
|
+
|
6
|
+
from ctools import call
|
7
|
+
|
8
|
+
thread_local = threading.local()
|
9
|
+
|
10
|
+
_threadPool: ThreadPoolExecutor = None
|
11
|
+
|
12
|
+
@call.init
|
13
|
+
def init():
|
14
|
+
global _threadPool
|
15
|
+
max_work_num = min(32, (os.cpu_count() or 1) + 4) # 最多 32 个
|
16
|
+
_threadPool = ThreadPoolExecutor(max_workers= max_work_num, thread_name_prefix='ck-')
|
17
|
+
|
18
|
+
def cb(f, callback):
|
19
|
+
exc = f.exception()
|
20
|
+
if exc:
|
21
|
+
print(f"Task failed: {exc}")
|
22
|
+
if callback: callback(exc)
|
23
|
+
else:
|
24
|
+
if callback: callback(f.result())
|
25
|
+
|
26
|
+
def submit(func, *args, callback=None, **kwargs):
|
27
|
+
if _threadPool is None: raise Exception('thread pool is not init')
|
28
|
+
future = _threadPool.submit(func, *args, **kwargs)
|
29
|
+
future.add_done_callback(lambda f: cb(f, callback))
|
30
|
+
time.sleep(0.01)
|
31
|
+
return future
|
32
|
+
|
33
|
+
def shutdown(wait=True):
|
34
|
+
if _threadPool is None: raise Exception('thread pool is not init')
|
35
|
+
_threadPool.shutdown(wait=wait)
|
ctools/upload_tools.py
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
import os
|
2
|
+
|
3
|
+
from ctools import sys_log, date_utils
|
4
|
+
|
5
|
+
log = sys_log.flog
|
6
|
+
|
7
|
+
"""
|
8
|
+
文件上传服务
|
9
|
+
"""
|
10
|
+
|
11
|
+
|
12
|
+
def save(upload, output_dir: str, file_name: str = None):
|
13
|
+
"""
|
14
|
+
根据上传的upload对象保存上传文件
|
15
|
+
:param output_dir:
|
16
|
+
:param upload:
|
17
|
+
:param file_name:
|
18
|
+
:return: 保存文件路径
|
19
|
+
"""
|
20
|
+
|
21
|
+
# 确保文件夹存在
|
22
|
+
os.makedirs(output_dir, exist_ok=True)
|
23
|
+
|
24
|
+
unique_filename = file_name
|
25
|
+
if not unique_filename:
|
26
|
+
# 生成不重复的文件名,加上时间戳
|
27
|
+
file_name, ext = os.path.splitext(upload.raw_filename)
|
28
|
+
timestamp = date_utils.get_time()
|
29
|
+
unique_filename = f'{file_name}_{timestamp}{ext}'
|
30
|
+
else:
|
31
|
+
dot_index = unique_filename.find(".")
|
32
|
+
suffix = os.path.splitext(upload.raw_filename)[-1]
|
33
|
+
if dot_index != -1:
|
34
|
+
unique_filename = os.path.splitext(unique_filename)[0] + suffix
|
35
|
+
else:
|
36
|
+
unique_filename = unique_filename + suffix
|
37
|
+
save_path = os.path.join(output_dir, unique_filename)
|
38
|
+
upload.save(save_path, overwrite=True)
|
39
|
+
log.info("上传文件成功: %s" % save_path)
|
40
|
+
return file_name, save_path
|
ctools/win_canvas.py
ADDED
@@ -0,0 +1,83 @@
|
|
1
|
+
import tkinter as tk
|
2
|
+
from multiprocessing import Process, Queue
|
3
|
+
|
4
|
+
data_queue: Queue = None
|
5
|
+
canvas_process: Process = None
|
6
|
+
|
7
|
+
class MSGType:
|
8
|
+
BOTTOM = 'bottom' #置于底部
|
9
|
+
DRAW = 'draw' #绘制矩形
|
10
|
+
|
11
|
+
class CanvasInfo:
|
12
|
+
def __init__(self,title: str='', points: list=None, msg_type: MSGType=MSGType.DRAW):
|
13
|
+
self.msg_type = msg_type
|
14
|
+
# 标题
|
15
|
+
self.title = title
|
16
|
+
# 左上, 右上, 右下, 左下
|
17
|
+
# [(100, 100), (200, 100), (200, 150), (100, 150)]
|
18
|
+
self.points = points
|
19
|
+
|
20
|
+
def on_ctrl_click(event):
|
21
|
+
print("Ctrl+Left Click detected")
|
22
|
+
|
23
|
+
class RecorderTool(tk.Tk):
|
24
|
+
def __init__(self, data: Queue):
|
25
|
+
super().__init__()
|
26
|
+
self.data = data
|
27
|
+
self.title('Recorder Tool')
|
28
|
+
self.attributes('-topmost', True)
|
29
|
+
self.overrideredirect(True)
|
30
|
+
self.attributes('-transparentcolor', 'grey')
|
31
|
+
self.geometry("{0}x{1}+0+0".format(self.winfo_screenwidth(), self.winfo_screenheight()))
|
32
|
+
self.canvas = tk.Canvas(self, highlightthickness=0, bg='grey')
|
33
|
+
self.canvas.pack(fill="both", expand=True)
|
34
|
+
self.bind('<Control-Button-1>', on_ctrl_click)
|
35
|
+
|
36
|
+
self.check_queue()
|
37
|
+
|
38
|
+
def draw_red_border(self, canvas_info: CanvasInfo):
|
39
|
+
self.clear_canvas()
|
40
|
+
points = canvas_info.points
|
41
|
+
x1, y1 = points[0]
|
42
|
+
x2, y2 = points[1]
|
43
|
+
x3, y3 = points[2]
|
44
|
+
x4, y4 = points[3]
|
45
|
+
self.canvas.create_line(x1, y1, x2, y2, fill="red", width=2)
|
46
|
+
self.canvas.create_line(x2, y2, x3, y3, fill="red", width=2)
|
47
|
+
self.canvas.create_line(x3, y3, x4, y4, fill="red", width=2)
|
48
|
+
self.canvas.create_line(x4, y4, x1, y1, fill="red", width=2)
|
49
|
+
text_x = (x1 + x2) / 2
|
50
|
+
text_y = y1 - 15
|
51
|
+
if text_y < 0: text_y = y3 + 15
|
52
|
+
self.canvas.create_text(text_x, text_y, text=canvas_info.title, font=("Arial", 12), fill="red")
|
53
|
+
|
54
|
+
def clear_canvas(self):
|
55
|
+
self.canvas.delete("all")
|
56
|
+
|
57
|
+
def check_queue(self):
|
58
|
+
if not self.data.empty():
|
59
|
+
canvas_info = self.data.get_nowait()
|
60
|
+
if canvas_info.msg_type == MSGType.BOTTOM:
|
61
|
+
self.clear_canvas()
|
62
|
+
self.withdraw()
|
63
|
+
elif canvas_info.msg_type == MSGType.DRAW:
|
64
|
+
self.deiconify()
|
65
|
+
self.draw_red_border(canvas_info)
|
66
|
+
self.after(10, self.check_queue)
|
67
|
+
|
68
|
+
def _init_recorder(data):
|
69
|
+
canvas_app = RecorderTool(data)
|
70
|
+
canvas_app.mainloop()
|
71
|
+
|
72
|
+
def start():
|
73
|
+
global data_queue, canvas_process
|
74
|
+
data_queue = Queue()
|
75
|
+
canvas_process = Process(target=_init_recorder, args=(data_queue,))
|
76
|
+
canvas_process.start()
|
77
|
+
return canvas_process
|
78
|
+
|
79
|
+
def stop():
|
80
|
+
canvas_process.terminate()
|
81
|
+
canvas_process.join()
|
82
|
+
data_queue.close()
|
83
|
+
|
ctools/win_control.py
ADDED
@@ -0,0 +1,106 @@
|
|
1
|
+
import os
|
2
|
+
import time
|
3
|
+
|
4
|
+
import pyautogui
|
5
|
+
import uiautomation as auto
|
6
|
+
from pynput import keyboard
|
7
|
+
|
8
|
+
from ctools import thread_pool, win_canvas, application, string_tools
|
9
|
+
|
10
|
+
current_control = None
|
11
|
+
ctrl_pressed = False
|
12
|
+
keyboard_listener = None
|
13
|
+
control_json = {}
|
14
|
+
screenshot_path = ""
|
15
|
+
|
16
|
+
class ControlInfo:
|
17
|
+
def __init__(self, ControlType, ClassName, AutomationId, Name, Depth):
|
18
|
+
self.ControlType = ControlType
|
19
|
+
self.ClassName = ClassName
|
20
|
+
self.AutomationId = AutomationId
|
21
|
+
self.Name = Name
|
22
|
+
#self.Depth = Depth
|
23
|
+
|
24
|
+
|
25
|
+
def get_control_from_cursor():
|
26
|
+
global control_json, screenshot_path
|
27
|
+
with auto.UIAutomationInitializerInThread():
|
28
|
+
win_canvas.data_queue.put(win_canvas.CanvasInfo(msg_type=win_canvas.MSGType.BOTTOM))
|
29
|
+
time.sleep(0.2)
|
30
|
+
try:
|
31
|
+
control = auto.ControlFromCursor()
|
32
|
+
except Exception as e:
|
33
|
+
print("No control found {}".format(e))
|
34
|
+
return
|
35
|
+
if control:
|
36
|
+
#当前控件信息
|
37
|
+
global current_control
|
38
|
+
current_control = control
|
39
|
+
#绘制矩形
|
40
|
+
canvas_info = win_canvas.CanvasInfo(control.Name, [
|
41
|
+
(control.BoundingRectangle.left, control.BoundingRectangle.top),
|
42
|
+
(control.BoundingRectangle.right, control.BoundingRectangle.top),
|
43
|
+
(control.BoundingRectangle.right, control.BoundingRectangle.bottom),
|
44
|
+
(control.BoundingRectangle.left, control.BoundingRectangle.bottom)
|
45
|
+
])
|
46
|
+
win_canvas.data_queue.put(canvas_info)
|
47
|
+
control_json = {}
|
48
|
+
c_info = ControlInfo(ControlType=current_control.ControlType, ClassName=current_control.ClassName, AutomationId=current_control.AutomationId, Name=current_control.Name, Depth=0)
|
49
|
+
_depth = 0
|
50
|
+
while current_control:
|
51
|
+
current_control = current_control.GetParentControl()
|
52
|
+
if current_control: _depth += 1
|
53
|
+
c_info.Depth = _depth
|
54
|
+
control_json.update(c_info.__dict__)
|
55
|
+
|
56
|
+
img = pyautogui.screenshot(region=[control.BoundingRectangle.left, control.BoundingRectangle.top,
|
57
|
+
control.BoundingRectangle.width(), control.BoundingRectangle.height()])
|
58
|
+
screenshot_path = os.path.join(application.Server.screenshotPath, "screenshot-%s.png" % string_tools.get_snowflake_id())
|
59
|
+
img.save(screenshot_path)
|
60
|
+
# xx = auto.Control(**control_json)
|
61
|
+
# print(control_json)
|
62
|
+
# time.sleep(2)
|
63
|
+
# xx.Click()
|
64
|
+
|
65
|
+
def on_press(key):
|
66
|
+
global ctrl_pressed, keyboard_listener
|
67
|
+
if key == keyboard.Key.ctrl_l and not ctrl_pressed:
|
68
|
+
ctrl_pressed = True
|
69
|
+
thread_pool.submit(get_control_from_cursor)
|
70
|
+
elif key == keyboard.Key.esc:
|
71
|
+
win_canvas.stop()
|
72
|
+
keyboard_listener.stop()
|
73
|
+
elif hasattr(key, 'vk') and key.vk == 192 and ctrl_pressed:
|
74
|
+
win_canvas.stop()
|
75
|
+
keyboard_listener.stop()
|
76
|
+
# pg.alert('采集成功!')
|
77
|
+
|
78
|
+
def on_release(key):
|
79
|
+
global ctrl_pressed
|
80
|
+
if key == keyboard.Key.ctrl_l:
|
81
|
+
ctrl_pressed = False
|
82
|
+
win_canvas.data_queue.put(win_canvas.CanvasInfo(msg_type=win_canvas.MSGType.BOTTOM))
|
83
|
+
|
84
|
+
|
85
|
+
def start():
|
86
|
+
global keyboard_listener
|
87
|
+
win_canvas.start()
|
88
|
+
keyboard_listener = keyboard.Listener(on_press=on_press, on_release=on_release)
|
89
|
+
keyboard_listener.start()
|
90
|
+
keyboard_listener.join()
|
91
|
+
|
92
|
+
|
93
|
+
def get_control_json():
|
94
|
+
global current_control, ctrl_pressed, keyboard_listener, control_json
|
95
|
+
current_control = None
|
96
|
+
ctrl_pressed = False
|
97
|
+
keyboard_listener = None
|
98
|
+
control_json = {}
|
99
|
+
start()
|
100
|
+
if len(control_json) == 0:
|
101
|
+
time.sleep(0.5)
|
102
|
+
return control_json, screenshot_path
|
103
|
+
|
104
|
+
if __name__ == '__main__':
|
105
|
+
a = get_control_json()
|
106
|
+
print(a)
|