kotonebot 0.5.0__py3-none-any.whl → 0.7.0__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.
Files changed (107) hide show
  1. kotonebot/__init__.py +39 -39
  2. kotonebot/backend/bot.py +312 -312
  3. kotonebot/backend/color.py +525 -525
  4. kotonebot/backend/context/__init__.py +3 -3
  5. kotonebot/backend/context/context.py +1002 -1002
  6. kotonebot/backend/context/task_action.py +183 -183
  7. kotonebot/backend/core.py +86 -129
  8. kotonebot/backend/debug/entry.py +89 -89
  9. kotonebot/backend/debug/mock.py +78 -78
  10. kotonebot/backend/debug/server.py +222 -222
  11. kotonebot/backend/debug/vars.py +351 -351
  12. kotonebot/backend/dispatch.py +227 -227
  13. kotonebot/backend/flow_controller.py +196 -196
  14. kotonebot/backend/image.py +36 -5
  15. kotonebot/backend/loop.py +222 -208
  16. kotonebot/backend/ocr.py +535 -535
  17. kotonebot/backend/preprocessor.py +103 -103
  18. kotonebot/client/__init__.py +9 -9
  19. kotonebot/client/device.py +369 -529
  20. kotonebot/client/fast_screenshot.py +377 -377
  21. kotonebot/client/host/__init__.py +43 -43
  22. kotonebot/client/host/adb_common.py +101 -107
  23. kotonebot/client/host/custom.py +118 -118
  24. kotonebot/client/host/leidian_host.py +196 -196
  25. kotonebot/client/host/mumu12_host.py +353 -353
  26. kotonebot/client/host/protocol.py +214 -214
  27. kotonebot/client/host/windows_common.py +73 -58
  28. kotonebot/client/implements/__init__.py +65 -70
  29. kotonebot/client/implements/adb.py +89 -89
  30. kotonebot/client/implements/nemu_ipc/__init__.py +11 -11
  31. kotonebot/client/implements/nemu_ipc/external_renderer_ipc.py +284 -284
  32. kotonebot/client/implements/nemu_ipc/nemu_ipc.py +327 -327
  33. kotonebot/client/implements/remote_windows.py +188 -188
  34. kotonebot/client/implements/uiautomator2.py +85 -85
  35. kotonebot/client/implements/windows/__init__.py +1 -0
  36. kotonebot/client/implements/windows/print_window.py +133 -0
  37. kotonebot/client/implements/windows/send_message.py +324 -0
  38. kotonebot/client/implements/{windows.py → windows/windows.py} +175 -176
  39. kotonebot/client/protocol.py +69 -69
  40. kotonebot/client/registration.py +24 -24
  41. kotonebot/client/scaler.py +467 -0
  42. kotonebot/config/base_config.py +103 -96
  43. kotonebot/config/config.py +61 -0
  44. kotonebot/config/manager.py +36 -36
  45. kotonebot/core/__init__.py +13 -0
  46. kotonebot/core/entities/base.py +182 -0
  47. kotonebot/core/entities/compound.py +75 -0
  48. kotonebot/core/entities/ocr.py +117 -0
  49. kotonebot/core/entities/template_match.py +198 -0
  50. kotonebot/devtools/__init__.py +42 -0
  51. kotonebot/devtools/cli/__init__.py +6 -0
  52. kotonebot/devtools/cli/main.py +53 -0
  53. kotonebot/{tools → devtools}/mirror.py +354 -354
  54. kotonebot/devtools/project/project.py +41 -0
  55. kotonebot/devtools/project/scanner.py +202 -0
  56. kotonebot/devtools/project/schema.py +99 -0
  57. kotonebot/devtools/resgen/__init__.py +42 -0
  58. kotonebot/devtools/resgen/codegen.py +331 -0
  59. kotonebot/devtools/resgen/core.py +94 -0
  60. kotonebot/devtools/resgen/parsers.py +360 -0
  61. kotonebot/devtools/resgen/utils.py +158 -0
  62. kotonebot/devtools/resgen/validation.py +115 -0
  63. kotonebot/devtools/web/dist/assets/bootstrap-icons-BOrJxbIo.woff +0 -0
  64. kotonebot/devtools/web/dist/assets/bootstrap-icons-BtvjY1KL.woff2 +0 -0
  65. kotonebot/devtools/web/dist/assets/ext-language_tools-CD021WJ2.js +2577 -0
  66. kotonebot/devtools/web/dist/assets/index-B_m5f2LF.js +2836 -0
  67. kotonebot/devtools/web/dist/assets/index-BlEDyGGa.css +9 -0
  68. kotonebot/devtools/web/dist/assets/language-client-C9muzqaq.js +128 -0
  69. kotonebot/devtools/web/dist/assets/mode-python-CtHp76XS.js +476 -0
  70. kotonebot/devtools/web/dist/icons/symbol-class.svg +3 -0
  71. kotonebot/devtools/web/dist/icons/symbol-file.svg +3 -0
  72. kotonebot/devtools/web/dist/icons/symbol-method.svg +3 -0
  73. kotonebot/devtools/web/dist/index.html +25 -0
  74. kotonebot/devtools/web/server/__init__.py +0 -0
  75. kotonebot/devtools/web/server/rest_api.py +217 -0
  76. kotonebot/devtools/web/server/server.py +85 -0
  77. kotonebot/errors.py +76 -76
  78. kotonebot/interop/win/__init__.py +13 -9
  79. kotonebot/interop/win/_mouse.py +310 -310
  80. kotonebot/interop/win/message_box.py +313 -313
  81. kotonebot/interop/win/reg.py +37 -37
  82. kotonebot/interop/win/shake_mouse.py +224 -0
  83. kotonebot/interop/win/shortcut.py +43 -43
  84. kotonebot/interop/win/task_dialog.py +513 -513
  85. kotonebot/interop/win/window.py +89 -0
  86. kotonebot/logging/__init__.py +2 -2
  87. kotonebot/logging/log.py +17 -17
  88. kotonebot/primitives/__init__.py +19 -17
  89. kotonebot/primitives/geometry.py +1067 -862
  90. kotonebot/primitives/visual.py +143 -63
  91. kotonebot/ui/file_host/sensio.py +36 -36
  92. kotonebot/ui/file_host/tmp_send.py +54 -54
  93. kotonebot/ui/pushkit/__init__.py +3 -3
  94. kotonebot/ui/pushkit/image_host.py +88 -88
  95. kotonebot/ui/pushkit/protocol.py +13 -13
  96. kotonebot/ui/pushkit/wxpusher.py +54 -54
  97. kotonebot/ui/user.py +148 -148
  98. kotonebot/util.py +436 -436
  99. {kotonebot-0.5.0.dist-info → kotonebot-0.7.0.dist-info}/METADATA +84 -82
  100. kotonebot-0.7.0.dist-info/RECORD +109 -0
  101. {kotonebot-0.5.0.dist-info → kotonebot-0.7.0.dist-info}/WHEEL +1 -1
  102. kotonebot-0.7.0.dist-info/entry_points.txt +2 -0
  103. {kotonebot-0.5.0.dist-info → kotonebot-0.7.0.dist-info}/licenses/LICENSE +673 -673
  104. kotonebot/client/implements/adb_raw.py +0 -163
  105. kotonebot-0.5.0.dist-info/RECORD +0 -71
  106. /kotonebot/{tools → devtools/project}/__init__.py +0 -0
  107. {kotonebot-0.5.0.dist-info → kotonebot-0.7.0.dist-info}/top_level.txt +0 -0
@@ -1,314 +1,314 @@
1
- import ctypes
2
- from typing import Optional, Literal, List, overload
3
- from typing_extensions import assert_never
4
-
5
-
6
- # 按钮常量
7
- MB_OK = 0x00000000
8
- MB_OKCANCEL = 0x00000001
9
- MB_ABORTRETRYIGNORE = 0x00000002
10
- MB_YESNOCANCEL = 0x00000003
11
- MB_YESNO = 0x00000004
12
- MB_RETRYCANCEL = 0x00000005
13
- MB_CANCELTRYCONTINUE = 0x00000006
14
-
15
- # 图标常量
16
- MB_ICONSTOP = 0x00000010
17
- MB_ICONERROR = 0x00000010
18
- MB_ICONQUESTION = 0x00000020
19
- MB_ICONWARNING = 0x00000030
20
- MB_ICONINFORMATION = 0x00000040
21
-
22
- # 默认按钮常量
23
- MB_DEFBUTTON1 = 0x00000000
24
- MB_DEFBUTTON2 = 0x00000100
25
- MB_DEFBUTTON3 = 0x00000200
26
- MB_DEFBUTTON4 = 0x00000300
27
-
28
- # 模态常量
29
- MB_APPLMODAL = 0x00000000
30
- MB_SYSTEMMODAL = 0x00001000
31
- MB_TASKMODAL = 0x00002000
32
-
33
- # 其他选项
34
- MB_HELP = 0x00004000
35
- MB_NOFOCUS = 0x00008000
36
- MB_SETFOREGROUND = 0x00010000
37
- MB_DEFAULT_DESKTOP_ONLY = 0x00020000
38
- MB_TOPMOST = 0x00040000
39
- MB_RIGHT = 0x00080000
40
- MB_RTLREADING = 0x00100000
41
- MB_SERVICE_NOTIFICATION = 0x00200000
42
-
43
- # 返回值常量
44
- IDOK = 1
45
- IDCANCEL = 2
46
- IDABORT = 3
47
- IDRETRY = 4
48
- IDIGNORE = 5
49
- IDYES = 6
50
- IDNO = 7
51
- IDCLOSE = 8
52
- IDHELP = 9
53
- IDTRYAGAIN = 10
54
- IDCONTINUE = 11
55
-
56
- # 为清晰起见,定义类型别名
57
- ButtonsType = Literal['ok', 'ok_cancel', 'abort_retry_ignore', 'yes_no_cancel', 'yes_no', 'retry_cancel', 'cancel_try_continue']
58
- IconType = Optional[Literal['stop', 'error', 'question', 'warning', 'information']]
59
- DefaultButtonType = Literal['button1', 'button2', 'button3', 'button4']
60
- ModalType = Literal['application', 'system', 'task']
61
- OptionsType = Optional[List[Literal['help', 'no_focus', 'set_foreground', 'default_desktop_only', 'topmost', 'right', 'rtl_reading', 'service_notification']]]
62
- ReturnType = Literal['ok', 'cancel', 'abort', 'retry', 'ignore', 'yes', 'no', 'close', 'help', 'try_again', 'continue']
63
-
64
- user32 = ctypes.windll.user32
65
-
66
-
67
- @overload
68
- def message_box(
69
- hWnd: Optional[int],
70
- text: str,
71
- caption: str,
72
- buttons: Literal['ok'] = 'ok',
73
- icon: IconType = None,
74
- default_button: DefaultButtonType = 'button1',
75
- modal: ModalType = 'application',
76
- options: OptionsType = None
77
- ) -> Literal['ok']: ...
78
-
79
-
80
- @overload
81
- def message_box(
82
- hWnd: Optional[int],
83
- text: str,
84
- caption: str,
85
- buttons: Literal['ok_cancel'],
86
- icon: IconType = None,
87
- default_button: DefaultButtonType = 'button1',
88
- modal: ModalType = 'application',
89
- options: OptionsType = None
90
- ) -> Literal['ok', 'cancel']: ...
91
-
92
-
93
- @overload
94
- def message_box(
95
- hWnd: Optional[int],
96
- text: str,
97
- caption: str,
98
- buttons: Literal['abort_retry_ignore'],
99
- icon: IconType = None,
100
- default_button: DefaultButtonType = 'button1',
101
- modal: ModalType = 'application',
102
- options: OptionsType = None
103
- ) -> Literal['abort', 'retry', 'ignore']: ...
104
-
105
-
106
- @overload
107
- def message_box(
108
- hWnd: Optional[int],
109
- text: str,
110
- caption: str,
111
- buttons: Literal['yes_no_cancel'],
112
- icon: IconType = None,
113
- default_button: DefaultButtonType = 'button1',
114
- modal: ModalType = 'application',
115
- options: OptionsType = None
116
- ) -> Literal['yes', 'no', 'cancel']: ...
117
-
118
-
119
- @overload
120
- def message_box(
121
- hWnd: Optional[int],
122
- text: str,
123
- caption: str,
124
- buttons: Literal['yes_no'],
125
- icon: IconType = None,
126
- default_button: DefaultButtonType = 'button1',
127
- modal: ModalType = 'application',
128
- options: OptionsType = None
129
- ) -> Literal['yes', 'no']: ...
130
-
131
-
132
- @overload
133
- def message_box(
134
- hWnd: Optional[int],
135
- text: str,
136
- caption: str,
137
- buttons: Literal['retry_cancel'],
138
- icon: IconType = None,
139
- default_button: DefaultButtonType = 'button1',
140
- modal: ModalType = 'application',
141
- options: OptionsType = None
142
- ) -> Literal['retry', 'cancel']: ...
143
-
144
-
145
- @overload
146
- def message_box(
147
- hWnd: Optional[int],
148
- text: str,
149
- caption: str,
150
- buttons: Literal['cancel_try_continue'],
151
- icon: IconType = None,
152
- default_button: DefaultButtonType = 'button1',
153
- modal: ModalType = 'application',
154
- options: OptionsType = None
155
- ) -> Literal['cancel', 'try_again', 'continue']: ...
156
-
157
-
158
- def message_box(
159
- hWnd: Optional[int],
160
- text: str,
161
- caption: str,
162
- buttons: ButtonsType = 'ok',
163
- icon: IconType = None,
164
- default_button: DefaultButtonType = 'button1',
165
- modal: ModalType = 'application',
166
- options: OptionsType = None
167
- ) -> ReturnType:
168
- """
169
- 显示消息框。
170
-
171
- :param hWnd: 所属窗口的句柄。可以为 None。
172
- :param text: 要显示的消息。
173
- :param caption: 消息框的标题。
174
- :param buttons: 要显示的按钮。
175
- :param icon: 要显示的图标。
176
- :param default_button: 默认按钮。
177
- :param modal: 消息框的模态。
178
- :param options: 其他杂项选项列表。
179
- :return: 表示用户点击的按钮的字符串。
180
- """
181
- uType = 0
182
-
183
- # --- 按钮类型 ---
184
- match buttons:
185
- case 'ok':
186
- uType |= MB_OK
187
- case 'ok_cancel':
188
- uType |= MB_OKCANCEL
189
- case 'abort_retry_ignore':
190
- uType |= MB_ABORTRETRYIGNORE
191
- case 'yes_no_cancel':
192
- uType |= MB_YESNOCANCEL
193
- case 'yes_no':
194
- uType |= MB_YESNO
195
- case 'retry_cancel':
196
- uType |= MB_RETRYCANCEL
197
- case 'cancel_try_continue':
198
- uType |= MB_CANCELTRYCONTINUE
199
- case _:
200
- assert_never(buttons)
201
-
202
- # --- 图标类型 ---
203
- if icon:
204
- match icon:
205
- case 'stop' | 'error':
206
- uType |= MB_ICONSTOP
207
- case 'question':
208
- uType |= MB_ICONQUESTION
209
- case 'warning':
210
- uType |= MB_ICONWARNING
211
- case 'information':
212
- uType |= MB_ICONINFORMATION
213
- case _:
214
- assert_never(icon)
215
-
216
- # --- 默认按钮 ---
217
- match default_button:
218
- case 'button1':
219
- uType |= MB_DEFBUTTON1
220
- case 'button2':
221
- uType |= MB_DEFBUTTON2
222
- case 'button3':
223
- uType |= MB_DEFBUTTON3
224
- case 'button4':
225
- uType |= MB_DEFBUTTON4
226
- case _:
227
- assert_never(default_button)
228
-
229
- # --- 模态 ---
230
- match modal:
231
- case 'application':
232
- uType |= MB_APPLMODAL
233
- case 'system':
234
- uType |= MB_SYSTEMMODAL
235
- case 'task':
236
- uType |= MB_TASKMODAL
237
- case _:
238
- assert_never(modal)
239
-
240
- # --- 其他选项 ---
241
- if options:
242
- for option in options:
243
- match option:
244
- case 'help':
245
- uType |= MB_HELP
246
- case 'no_focus':
247
- uType |= MB_NOFOCUS
248
- case 'set_foreground':
249
- uType |= MB_SETFOREGROUND
250
- case 'default_desktop_only':
251
- uType |= MB_DEFAULT_DESKTOP_ONLY
252
- case 'topmost':
253
- uType |= MB_TOPMOST
254
- case 'right':
255
- uType |= MB_RIGHT
256
- case 'rtl_reading':
257
- uType |= MB_RTLREADING
258
- case 'service_notification':
259
- uType |= MB_SERVICE_NOTIFICATION
260
- case _:
261
- assert_never(option)
262
-
263
- result = user32.MessageBoxW(hWnd, text, caption, uType)
264
-
265
- match result:
266
- case 1: # IDOK
267
- return 'ok'
268
- case 2: # IDCANCEL
269
- return 'cancel'
270
- case 3: # IDABORT
271
- return 'abort'
272
- case 4: # IDRETRY
273
- return 'retry'
274
- case 5: # IDIGNORE
275
- return 'ignore'
276
- case 6: # IDYES
277
- return 'yes'
278
- case 7: # IDNO
279
- return 'no'
280
- case 8: # IDCLOSE
281
- return 'close'
282
- case 9: # IDHELP
283
- return 'help'
284
- case 10: # IDTRYAGAIN
285
- return 'try_again'
286
- case 11: # IDCONTINUE
287
- return 'continue'
288
- case _:
289
- # 对于标准消息框,不应发生这种情况
290
- raise RuntimeError(f"Unknown MessageBox return code: {result}")
291
-
292
-
293
- if __name__ == '__main__':
294
- # 示例用法
295
- response = message_box(
296
- None,
297
- "是否要退出程序?",
298
- "确认",
299
- buttons='yes_no',
300
- icon='question'
301
- )
302
-
303
- if response == 'yes':
304
- print("程序退出。")
305
- else:
306
- print("程序继续运行。")
307
-
308
- message_box(
309
- None,
310
- "操作已完成。",
311
- "通知",
312
- buttons='ok',
313
- icon='information'
1
+ import ctypes
2
+ from typing import Optional, Literal, List, overload
3
+ from typing_extensions import assert_never
4
+
5
+
6
+ # 按钮常量
7
+ MB_OK = 0x00000000
8
+ MB_OKCANCEL = 0x00000001
9
+ MB_ABORTRETRYIGNORE = 0x00000002
10
+ MB_YESNOCANCEL = 0x00000003
11
+ MB_YESNO = 0x00000004
12
+ MB_RETRYCANCEL = 0x00000005
13
+ MB_CANCELTRYCONTINUE = 0x00000006
14
+
15
+ # 图标常量
16
+ MB_ICONSTOP = 0x00000010
17
+ MB_ICONERROR = 0x00000010
18
+ MB_ICONQUESTION = 0x00000020
19
+ MB_ICONWARNING = 0x00000030
20
+ MB_ICONINFORMATION = 0x00000040
21
+
22
+ # 默认按钮常量
23
+ MB_DEFBUTTON1 = 0x00000000
24
+ MB_DEFBUTTON2 = 0x00000100
25
+ MB_DEFBUTTON3 = 0x00000200
26
+ MB_DEFBUTTON4 = 0x00000300
27
+
28
+ # 模态常量
29
+ MB_APPLMODAL = 0x00000000
30
+ MB_SYSTEMMODAL = 0x00001000
31
+ MB_TASKMODAL = 0x00002000
32
+
33
+ # 其他选项
34
+ MB_HELP = 0x00004000
35
+ MB_NOFOCUS = 0x00008000
36
+ MB_SETFOREGROUND = 0x00010000
37
+ MB_DEFAULT_DESKTOP_ONLY = 0x00020000
38
+ MB_TOPMOST = 0x00040000
39
+ MB_RIGHT = 0x00080000
40
+ MB_RTLREADING = 0x00100000
41
+ MB_SERVICE_NOTIFICATION = 0x00200000
42
+
43
+ # 返回值常量
44
+ IDOK = 1
45
+ IDCANCEL = 2
46
+ IDABORT = 3
47
+ IDRETRY = 4
48
+ IDIGNORE = 5
49
+ IDYES = 6
50
+ IDNO = 7
51
+ IDCLOSE = 8
52
+ IDHELP = 9
53
+ IDTRYAGAIN = 10
54
+ IDCONTINUE = 11
55
+
56
+ # 为清晰起见,定义类型别名
57
+ ButtonsType = Literal['ok', 'ok_cancel', 'abort_retry_ignore', 'yes_no_cancel', 'yes_no', 'retry_cancel', 'cancel_try_continue']
58
+ IconType = Optional[Literal['stop', 'error', 'question', 'warning', 'information']]
59
+ DefaultButtonType = Literal['button1', 'button2', 'button3', 'button4']
60
+ ModalType = Literal['application', 'system', 'task']
61
+ OptionsType = Optional[List[Literal['help', 'no_focus', 'set_foreground', 'default_desktop_only', 'topmost', 'right', 'rtl_reading', 'service_notification']]]
62
+ ReturnType = Literal['ok', 'cancel', 'abort', 'retry', 'ignore', 'yes', 'no', 'close', 'help', 'try_again', 'continue']
63
+
64
+ user32 = ctypes.windll.user32
65
+
66
+
67
+ @overload
68
+ def message_box(
69
+ hWnd: Optional[int],
70
+ text: str,
71
+ caption: str,
72
+ buttons: Literal['ok'] = 'ok',
73
+ icon: IconType = None,
74
+ default_button: DefaultButtonType = 'button1',
75
+ modal: ModalType = 'application',
76
+ options: OptionsType = None
77
+ ) -> Literal['ok']: ...
78
+
79
+
80
+ @overload
81
+ def message_box(
82
+ hWnd: Optional[int],
83
+ text: str,
84
+ caption: str,
85
+ buttons: Literal['ok_cancel'],
86
+ icon: IconType = None,
87
+ default_button: DefaultButtonType = 'button1',
88
+ modal: ModalType = 'application',
89
+ options: OptionsType = None
90
+ ) -> Literal['ok', 'cancel']: ...
91
+
92
+
93
+ @overload
94
+ def message_box(
95
+ hWnd: Optional[int],
96
+ text: str,
97
+ caption: str,
98
+ buttons: Literal['abort_retry_ignore'],
99
+ icon: IconType = None,
100
+ default_button: DefaultButtonType = 'button1',
101
+ modal: ModalType = 'application',
102
+ options: OptionsType = None
103
+ ) -> Literal['abort', 'retry', 'ignore']: ...
104
+
105
+
106
+ @overload
107
+ def message_box(
108
+ hWnd: Optional[int],
109
+ text: str,
110
+ caption: str,
111
+ buttons: Literal['yes_no_cancel'],
112
+ icon: IconType = None,
113
+ default_button: DefaultButtonType = 'button1',
114
+ modal: ModalType = 'application',
115
+ options: OptionsType = None
116
+ ) -> Literal['yes', 'no', 'cancel']: ...
117
+
118
+
119
+ @overload
120
+ def message_box(
121
+ hWnd: Optional[int],
122
+ text: str,
123
+ caption: str,
124
+ buttons: Literal['yes_no'],
125
+ icon: IconType = None,
126
+ default_button: DefaultButtonType = 'button1',
127
+ modal: ModalType = 'application',
128
+ options: OptionsType = None
129
+ ) -> Literal['yes', 'no']: ...
130
+
131
+
132
+ @overload
133
+ def message_box(
134
+ hWnd: Optional[int],
135
+ text: str,
136
+ caption: str,
137
+ buttons: Literal['retry_cancel'],
138
+ icon: IconType = None,
139
+ default_button: DefaultButtonType = 'button1',
140
+ modal: ModalType = 'application',
141
+ options: OptionsType = None
142
+ ) -> Literal['retry', 'cancel']: ...
143
+
144
+
145
+ @overload
146
+ def message_box(
147
+ hWnd: Optional[int],
148
+ text: str,
149
+ caption: str,
150
+ buttons: Literal['cancel_try_continue'],
151
+ icon: IconType = None,
152
+ default_button: DefaultButtonType = 'button1',
153
+ modal: ModalType = 'application',
154
+ options: OptionsType = None
155
+ ) -> Literal['cancel', 'try_again', 'continue']: ...
156
+
157
+
158
+ def message_box(
159
+ hWnd: Optional[int],
160
+ text: str,
161
+ caption: str,
162
+ buttons: ButtonsType = 'ok',
163
+ icon: IconType = None,
164
+ default_button: DefaultButtonType = 'button1',
165
+ modal: ModalType = 'application',
166
+ options: OptionsType = None
167
+ ) -> ReturnType:
168
+ """
169
+ 显示消息框。
170
+
171
+ :param hWnd: 所属窗口的句柄。可以为 None。
172
+ :param text: 要显示的消息。
173
+ :param caption: 消息框的标题。
174
+ :param buttons: 要显示的按钮。
175
+ :param icon: 要显示的图标。
176
+ :param default_button: 默认按钮。
177
+ :param modal: 消息框的模态。
178
+ :param options: 其他杂项选项列表。
179
+ :return: 表示用户点击的按钮的字符串。
180
+ """
181
+ uType = 0
182
+
183
+ # --- 按钮类型 ---
184
+ match buttons:
185
+ case 'ok':
186
+ uType |= MB_OK
187
+ case 'ok_cancel':
188
+ uType |= MB_OKCANCEL
189
+ case 'abort_retry_ignore':
190
+ uType |= MB_ABORTRETRYIGNORE
191
+ case 'yes_no_cancel':
192
+ uType |= MB_YESNOCANCEL
193
+ case 'yes_no':
194
+ uType |= MB_YESNO
195
+ case 'retry_cancel':
196
+ uType |= MB_RETRYCANCEL
197
+ case 'cancel_try_continue':
198
+ uType |= MB_CANCELTRYCONTINUE
199
+ case _:
200
+ assert_never(buttons)
201
+
202
+ # --- 图标类型 ---
203
+ if icon:
204
+ match icon:
205
+ case 'stop' | 'error':
206
+ uType |= MB_ICONSTOP
207
+ case 'question':
208
+ uType |= MB_ICONQUESTION
209
+ case 'warning':
210
+ uType |= MB_ICONWARNING
211
+ case 'information':
212
+ uType |= MB_ICONINFORMATION
213
+ case _:
214
+ assert_never(icon)
215
+
216
+ # --- 默认按钮 ---
217
+ match default_button:
218
+ case 'button1':
219
+ uType |= MB_DEFBUTTON1
220
+ case 'button2':
221
+ uType |= MB_DEFBUTTON2
222
+ case 'button3':
223
+ uType |= MB_DEFBUTTON3
224
+ case 'button4':
225
+ uType |= MB_DEFBUTTON4
226
+ case _:
227
+ assert_never(default_button)
228
+
229
+ # --- 模态 ---
230
+ match modal:
231
+ case 'application':
232
+ uType |= MB_APPLMODAL
233
+ case 'system':
234
+ uType |= MB_SYSTEMMODAL
235
+ case 'task':
236
+ uType |= MB_TASKMODAL
237
+ case _:
238
+ assert_never(modal)
239
+
240
+ # --- 其他选项 ---
241
+ if options:
242
+ for option in options:
243
+ match option:
244
+ case 'help':
245
+ uType |= MB_HELP
246
+ case 'no_focus':
247
+ uType |= MB_NOFOCUS
248
+ case 'set_foreground':
249
+ uType |= MB_SETFOREGROUND
250
+ case 'default_desktop_only':
251
+ uType |= MB_DEFAULT_DESKTOP_ONLY
252
+ case 'topmost':
253
+ uType |= MB_TOPMOST
254
+ case 'right':
255
+ uType |= MB_RIGHT
256
+ case 'rtl_reading':
257
+ uType |= MB_RTLREADING
258
+ case 'service_notification':
259
+ uType |= MB_SERVICE_NOTIFICATION
260
+ case _:
261
+ assert_never(option)
262
+
263
+ result = user32.MessageBoxW(hWnd, text, caption, uType)
264
+
265
+ match result:
266
+ case 1: # IDOK
267
+ return 'ok'
268
+ case 2: # IDCANCEL
269
+ return 'cancel'
270
+ case 3: # IDABORT
271
+ return 'abort'
272
+ case 4: # IDRETRY
273
+ return 'retry'
274
+ case 5: # IDIGNORE
275
+ return 'ignore'
276
+ case 6: # IDYES
277
+ return 'yes'
278
+ case 7: # IDNO
279
+ return 'no'
280
+ case 8: # IDCLOSE
281
+ return 'close'
282
+ case 9: # IDHELP
283
+ return 'help'
284
+ case 10: # IDTRYAGAIN
285
+ return 'try_again'
286
+ case 11: # IDCONTINUE
287
+ return 'continue'
288
+ case _:
289
+ # 对于标准消息框,不应发生这种情况
290
+ raise RuntimeError(f"Unknown MessageBox return code: {result}")
291
+
292
+
293
+ if __name__ == '__main__':
294
+ # 示例用法
295
+ response = message_box(
296
+ None,
297
+ "是否要退出程序?",
298
+ "确认",
299
+ buttons='yes_no',
300
+ icon='question'
301
+ )
302
+
303
+ if response == 'yes':
304
+ print("程序退出。")
305
+ else:
306
+ print("程序继续运行。")
307
+
308
+ message_box(
309
+ None,
310
+ "操作已完成。",
311
+ "通知",
312
+ buttons='ok',
313
+ icon='information'
314
314
  )