simconnect-H 0.2.0__tar.gz → 0.2.2__tar.gz

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.
@@ -1,4 +1,4 @@
1
- MIT License
1
+ # MIT License
2
2
 
3
3
  Copyright (c) 2026 HuJie
4
4
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: simconnect-H
3
- Version: 0.2.0
3
+ Version: 0.2.2
4
4
  Summary: 原生 ctypes SimConnect 库 — 零外部依赖,直接加载 SimConnect.dll 与 MSFS 通讯
5
5
  Author-email: HuJie <150501351+hjznb887@users.noreply.github.com>
6
6
  License-Expression: MIT
@@ -164,7 +164,7 @@ with SimConnect() as sc:
164
164
  | ------ | ------ |
165
165
  | `find_simconnect_dll()` | 自动搜索 SimConnect.dll 路径 |
166
166
  | `read_data_value(pData, datatype=0)` | 从 dispatch 回调中读取指定类型数据 |
167
- | `__version__` | 当前库版本 `"0.2.0"` |
167
+ | `__version__` | 当前库版本 `"0.2.2"` |
168
168
 
169
169
  ## 许可证
170
170
 
@@ -145,7 +145,7 @@ with SimConnect() as sc:
145
145
  | ------ | ------ |
146
146
  | `find_simconnect_dll()` | 自动搜索 SimConnect.dll 路径 |
147
147
  | `read_data_value(pData, datatype=0)` | 从 dispatch 回调中读取指定类型数据 |
148
- | `__version__` | 当前库版本 `"0.2.0"` |
148
+ | `__version__` | 当前库版本 `"0.2.2"` |
149
149
 
150
150
  ## 许可证
151
151
 
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "simconnect-H"
7
- version = "0.2.0"
7
+ version = "0.2.2"
8
8
  description = "原生 ctypes SimConnect 库 — 零外部依赖,直接加载 SimConnect.dll 与 MSFS 通讯"
9
9
  readme = "README.md"
10
10
  license = "MIT"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: simconnect-H
3
- Version: 0.2.0
3
+ Version: 0.2.2
4
4
  Summary: 原生 ctypes SimConnect 库 — 零外部依赖,直接加载 SimConnect.dll 与 MSFS 通讯
5
5
  Author-email: HuJie <150501351+hjznb887@users.noreply.github.com>
6
6
  License-Expression: MIT
@@ -164,7 +164,7 @@ with SimConnect() as sc:
164
164
  | ------ | ------ |
165
165
  | `find_simconnect_dll()` | 自动搜索 SimConnect.dll 路径 |
166
166
  | `read_data_value(pData, datatype=0)` | 从 dispatch 回调中读取指定类型数据 |
167
- | `__version__` | 当前库版本 `"0.2.0"` |
167
+ | `__version__` | 当前库版本 `"0.2.2"` |
168
168
 
169
169
  ## 许可证
170
170
 
@@ -30,6 +30,7 @@ import os
30
30
  import time
31
31
  import logging
32
32
  import threading
33
+ from typing import Callable, Optional, Any, Tuple
33
34
  from ctypes import (c_ulong, c_float, c_char_p, c_double, c_void_p, c_int32, c_int16, c_int8,
34
35
  cast, POINTER, sizeof as c_sizeof, Structure, WinDLL, byref)
35
36
  from ctypes.wintypes import HANDLE, DWORD, HRESULT
@@ -69,7 +70,7 @@ logger = logging.getLogger(__name__)
69
70
  # 版本
70
71
  # ═══════════════════════════════════════════════════
71
72
 
72
- __version__ = "0.2.0"
73
+ __version__ = "0.2.2"
73
74
 
74
75
  # ═══════════════════════════════════════════════════
75
76
  # 常量
@@ -201,7 +202,7 @@ MSFS_EVENTS = {
201
202
  # DLL 查找
202
203
  # ═══════════════════════════════════════════════════
203
204
 
204
- def find_simconnect_dll():
205
+ def find_simconnect_dll() -> str:
205
206
  """查找 SimConnect.dll 位置。
206
207
 
207
208
  搜索顺序:
@@ -241,7 +242,7 @@ def find_simconnect_dll():
241
242
  # 模块级便利函数
242
243
  # ═══════════════════════════════════════════════════
243
244
 
244
- def read_data_value(pData, datatype=0):
245
+ def read_data_value(pData: Any, datatype: int = 0) -> Any:
245
246
  """从 dispatch 回调的 pData 中读取指定类型的数据。
246
247
 
247
248
  用法:
@@ -287,38 +288,38 @@ class SimConnect:
287
288
  # ── 属性 ──────────────────────────────────────
288
289
 
289
290
  @property
290
- def handle(self):
291
+ def handle(self) -> Optional[HANDLE]:
291
292
  """SimConnect 句柄(HANDLE),未连接时为 None"""
292
293
  return self._hSimConnect
293
294
 
294
295
  @property
295
- def dll(self):
296
+ def dll(self) -> Optional[WinDLL]:
296
297
  """已加载的 WinDLL 对象,未加载时为 None"""
297
298
  return self._dll
298
299
 
299
300
  @property
300
- def is_open(self):
301
+ def is_open(self) -> bool:
301
302
  """是否已成功打开连接"""
302
303
  return (self._hSimConnect is not None
303
304
  and self._hSimConnect.value is not None
304
305
  and self._hSimConnect.value != 0)
305
306
 
306
- def __repr__(self):
307
+ def __repr__(self) -> str:
307
308
  status = "已连接" if self.is_open else "未连接"
308
309
  dll_status = "已加载" if self._dll else "未加载"
309
310
  return f"<SimConnect {status}, DLL {dll_status}>"
310
311
 
311
- def __enter__(self):
312
+ def __enter__(self) -> 'SimConnect':
312
313
  """支持 with 语句 — 返回自身"""
313
314
  return self
314
315
 
315
- def __exit__(self, exc_type, exc_val, exc_tb):
316
+ def __exit__(self, exc_type: Any, exc_val: Any, exc_tb: Any) -> None:
316
317
  """退出 with 块时自动关闭连接"""
317
318
  self.close()
318
319
 
319
320
  # ── 初始化 ────────────────────────────────────
320
321
 
321
- def load_dll(self, dll_path=None):
322
+ def load_dll(self, dll_path: Optional[str] = None) -> None:
322
323
  """加载 SimConnect.dll。
323
324
 
324
325
  Args:
@@ -364,7 +365,10 @@ class SimConnect:
364
365
  d.SimConnect_Close.argtypes = [HANDLE]
365
366
 
366
367
  # SimConnect_CallDispatch
367
- self._DispatchProc = ctypes.WINFUNCTYPE(None, c_void_p, DWORD, c_void_p)
368
+ # 第一个参数必须是 POINTER(SIMCONNECT_RECV),c_void_p 会导致 .contents.dwID 失败
369
+ self._DispatchProc = ctypes.WINFUNCTYPE(
370
+ None, POINTER(SIMCONNECT_RECV), DWORD, c_void_p,
371
+ )
368
372
  d.SimConnect_CallDispatch.restype = HRESULT
369
373
  d.SimConnect_CallDispatch.argtypes = [HANDLE, self._DispatchProc, c_void_p]
370
374
 
@@ -414,8 +418,9 @@ class SimConnect:
414
418
 
415
419
  # ── 连接管理 ──────────────────────────────────
416
420
 
417
- def open(self, app_name=b"SimConnectApp", window_handle=None, fifo_size=0,
418
- window_event_handle=None, config_index=0):
421
+ def open(self, app_name: bytes = b"SimConnectApp", window_handle: Any = None,
422
+ fifo_size: int = 0, window_event_handle: Any = None,
423
+ config_index: int = 0) -> HANDLE:
419
424
  """建立与 MSFS 的 SimConnect 连接。
420
425
 
421
426
  Args:
@@ -452,47 +457,50 @@ class SimConnect:
452
457
  logger.info("SimConnect 已连接 (app=%s)", app_name)
453
458
  return hSim
454
459
 
455
- def close(self):
460
+ def close(self) -> None:
456
461
  """关闭 SimConnect 连接。"""
457
462
  self.stop_background_dispatch()
458
- if self._dll and self._hSimConnect:
463
+ with self._lock:
464
+ hSim = self._hSimConnect
465
+ self._hSimConnect = None
466
+ if self._dll and hSim:
459
467
  try:
460
- self._dll.SimConnect_Close(self._hSimConnect)
468
+ self._dll.SimConnect_Close(hSim)
461
469
  logger.info("SimConnect 已断开")
462
470
  except Exception as e:
463
471
  logger.debug("SimConnect_Close 异常: %s", e)
464
- self._hSimConnect = None
465
472
 
466
473
  # ── dispatch ──────────────────────────────────
467
474
 
468
- def call_dispatch(self, callback):
475
+ def call_dispatch(self, callback: Callable) -> None:
469
476
  """设置并调用 dispatch 回调处理 SimConnect 消息。
470
477
 
471
478
  Args:
472
479
  callback: 回调函数,签名 (pData, cbData, pContext) -> None。
473
- 其中 pData 是 c_void_p,指向 SIMCONNECT_RECV 结构体。
480
+ 其中 pData 是 POINTER(SIMCONNECT_RECV),可直接访问 .contents.dwID。
474
481
  """
475
- if not self._dll or not self._hSimConnect:
482
+ if not self._dll:
476
483
  return
477
484
  with self._lock:
478
485
  self._dispatch_cb = self._DispatchProc(callback)
479
- self._dll.SimConnect_CallDispatch(
480
- self._hSimConnect, self._dispatch_cb, None
481
- )
486
+ cb = self._dispatch_cb
487
+ hSim = self._hSimConnect
488
+ if not hSim or not hSim.value:
489
+ return
490
+ self._dll.SimConnect_CallDispatch(hSim, cb, None)
482
491
 
483
- def dispatch(self):
492
+ def dispatch(self) -> None:
484
493
  """处理一次 SimConnect 消息队列。需要先通过 set_dispatch_cb() 设置回调。"""
485
- if not self._dll or not self._hSimConnect:
494
+ if not self._dll:
486
495
  return
487
496
  with self._lock:
488
497
  cb = self._dispatch_cb
489
- if not cb:
498
+ hSim = self._hSimConnect
499
+ if not cb or not hSim or not hSim.value:
490
500
  return
491
- self._dll.SimConnect_CallDispatch(
492
- self._hSimConnect, cb, None
493
- )
501
+ self._dll.SimConnect_CallDispatch(hSim, cb, None)
494
502
 
495
- def set_dispatch_cb(self, callback):
503
+ def set_dispatch_cb(self, callback: Callable) -> None:
496
504
  """设置 dispatch 回调函数(不触发调用)。
497
505
 
498
506
  Args:
@@ -503,7 +511,7 @@ class SimConnect:
503
511
 
504
512
  # ── 后台 dispatch 线程 ────────────────────────
505
513
 
506
- def start_background_dispatch(self, callback=None):
514
+ def start_background_dispatch(self, callback: Optional[Callable] = None) -> None:
507
515
  """启动后台线程持续 dispatch(适合高频率数据接收场景)。
508
516
 
509
517
  Args:
@@ -526,7 +534,7 @@ class SimConnect:
526
534
  self._dispatch_thread.start()
527
535
  logger.debug("后台 dispatch 线程已启动")
528
536
 
529
- def stop_background_dispatch(self):
537
+ def stop_background_dispatch(self) -> None:
530
538
  """停止后台 dispatch 线程。"""
531
539
  self._dispatch_running = False
532
540
  self._dispatch_stop_event.set() # 立即唤醒 dispatch 循环
@@ -562,8 +570,9 @@ class SimConnect:
562
570
 
563
571
  # ── 数据定义 ──────────────────────────────────
564
572
 
565
- def add_to_data_definition(self, define_id, simvar_name, unit,
566
- datatype=0, epsilon=0.0, datasize=0xFFFFFFFF):
573
+ def add_to_data_definition(self, define_id: int, simvar_name: bytes, unit: bytes,
574
+ datatype: int = 0, epsilon: float = 0.0,
575
+ datasize: int = 0xFFFFFFFF) -> int:
567
576
  """注册 SimVar 数据定义。
568
577
 
569
578
  Args:
@@ -582,7 +591,7 @@ class SimConnect:
582
591
  c_ulong(datatype), c_float(epsilon), DWORD(datasize),
583
592
  )
584
593
 
585
- def clear_data_definition(self, define_id):
594
+ def clear_data_definition(self, define_id: int) -> int:
586
595
  """清除数据定义。"""
587
596
  return self._dll.SimConnect_ClearDataDefinition(
588
597
  self._hSimConnect, DWORD(define_id)
@@ -590,8 +599,9 @@ class SimConnect:
590
599
 
591
600
  # ── 数据请求 ──────────────────────────────────
592
601
 
593
- def request_data_on_simobject_type(self, request_id, define_id,
594
- object_id=0, simobject_type=0):
602
+ def request_data_on_simobject_type(self, request_id: int, define_id: int,
603
+ object_id: int = 0,
604
+ simobject_type: int = 0) -> int:
595
605
  """请求指定类型的 SimObject 数据。
596
606
 
597
607
  Args:
@@ -605,8 +615,10 @@ class SimConnect:
605
615
  DWORD(object_id), c_ulong(simobject_type),
606
616
  )
607
617
 
608
- def request_data_on_simobject(self, request_id, define_id, object_id=0,
609
- period=4, flags=0, origin=0, interval=0, limit=0):
618
+ def request_data_on_simobject(self, request_id: int, define_id: int,
619
+ object_id: int = 0, period: int = 4,
620
+ flags: int = 0, origin: int = 0,
621
+ interval: int = 0, limit: int = 0) -> int:
610
622
  """请求指定 SimObject 的持续数据更新(更常用的 API)。
611
623
 
612
624
  Args:
@@ -625,8 +637,9 @@ class SimConnect:
625
637
  DWORD(origin), DWORD(interval), DWORD(limit),
626
638
  )
627
639
 
628
- def add_and_request(self, request_id, define_id, simvar_name, unit,
629
- datatype=0, period=4):
640
+ def add_and_request(self, request_id: int, define_id: int,
641
+ simvar_name: bytes, unit: bytes,
642
+ datatype: int = 0, period: int = 4) -> int:
630
643
  """注册定义并立即发起持续请求(一次性完成两个步骤)。
631
644
 
632
645
  Args:
@@ -644,8 +657,10 @@ class SimConnect:
644
657
 
645
658
  # ── 数据写入 ──────────────────────────────────
646
659
 
647
- def set_data_on_simobject(self, define_id, object_id=0,
648
- flags=0, array_count=1, unit_size=8, data_ptr=None):
660
+ def set_data_on_simobject(self, define_id: int, object_id: int = 0,
661
+ flags: int = 0, array_count: int = 1,
662
+ unit_size: int = 8,
663
+ data_ptr: Optional[c_void_p] = None) -> Optional[int]:
649
664
  """向 SimObject 写入数据。
650
665
 
651
666
  Args:
@@ -657,13 +672,13 @@ class SimConnect:
657
672
  data_ptr: 数据指针(c_void_p),为 None 时跳过。
658
673
  """
659
674
  if data_ptr is None:
660
- return
675
+ return None
661
676
  return self._dll.SimConnect_SetDataOnSimObject(
662
677
  self._hSimConnect, DWORD(define_id), c_ulong(object_id),
663
678
  DWORD(flags), DWORD(array_count), DWORD(unit_size), data_ptr,
664
679
  )
665
680
 
666
- def write_double(self, define_id, value):
681
+ def write_double(self, define_id: int, value: float) -> Optional[int]:
667
682
  """快捷方法:写入一个 double 值。
668
683
 
669
684
  Args:
@@ -676,7 +691,7 @@ class SimConnect:
676
691
  )
677
692
 
678
693
  @staticmethod
679
- def event_data_float(value):
694
+ def event_data_float(value: float) -> int:
680
695
  """将 float 转换为 DWORD 位表示(用于需要浮点参数的事件)。
681
696
 
682
697
  某些 SimConnect 事件(如襟翼角度)需要将 float 的二进制表示
@@ -689,7 +704,7 @@ class SimConnect:
689
704
 
690
705
  # ── 事件 ──────────────────────────────────────
691
706
 
692
- def map_client_event_to_sim_event(self, event_id, event_name):
707
+ def map_client_event_to_sim_event(self, event_id: int, event_name: bytes) -> int:
693
708
  """将客户端事件 ID 映射到 Sim 事件名称。
694
709
 
695
710
  Args:
@@ -700,8 +715,9 @@ class SimConnect:
700
715
  self._hSimConnect, DWORD(event_id), event_name,
701
716
  )
702
717
 
703
- def transmit_client_event(self, object_id=0, event_id=0, data=0,
704
- group_priority=0x19000000, flags=16):
718
+ def transmit_client_event(self, object_id: int = 0, event_id: int = 0,
719
+ data: int = 0, group_priority: int = 0x19000000,
720
+ flags: int = 16) -> int:
705
721
  """发送客户端事件到 SimObject。
706
722
 
707
723
  Args:
@@ -718,7 +734,7 @@ class SimConnect:
718
734
 
719
735
  # ── 系统事件 ──────────────────────────────────
720
736
 
721
- def subscribe_to_system_event(self, event_id, event_name):
737
+ def subscribe_to_system_event(self, event_id: int, event_name: bytes) -> int:
722
738
  """订阅系统事件。
723
739
 
724
740
  Args:
@@ -731,7 +747,7 @@ class SimConnect:
731
747
 
732
748
  # ── 工具 ──────────────────────────────────────
733
749
 
734
- def get_last_sent_packet_id(self):
750
+ def get_last_sent_packet_id(self) -> int:
735
751
  """获取最后发送的数据包 ID。"""
736
752
  pid = DWORD(0)
737
753
  self._dll.SimConnect_GetLastSentPacketID(
@@ -739,13 +755,13 @@ class SimConnect:
739
755
  )
740
756
  return pid.value
741
757
 
742
- def read_double(self, pData):
758
+ def read_double(self, pData: Any) -> Tuple[Optional[int], Optional[float]]:
743
759
  """从 dispatch 回调的 pData 中读取 double 值。
744
760
 
745
761
  用于 SIMCONNECT_RECV_ID_SIMOBJECT_DATA / _BYTYPE 消息。
746
762
 
747
763
  Args:
748
- pData: c_void_p,指向完整消息的指针。
764
+ pData: POINTER(SIMCONNECT_RECV),dispatch 回调的第一个参数。
749
765
 
750
766
  Returns:
751
767
  (request_id, float_value) 元组,解析失败返回 (None, None)。
@@ -759,13 +775,13 @@ class SimConnect:
759
775
  return None, None
760
776
 
761
777
  @staticmethod
762
- def read_data(pData, datatype=0):
778
+ def read_data(pData: Any, datatype: int = 0) -> Any:
763
779
  """从 dispatch 回调指针中按类型读取数据值。
764
780
 
765
781
  用于 dispatch 回调中解析不同类型的数据。
766
782
 
767
783
  Args:
768
- pData: c_void_p,指向消息体的指针(dispatch 回调的第一个参数)。
784
+ pData: POINTER(SIMCONNECT_RECV),dispatch 回调的第一个参数。
769
785
  datatype: SIMCONNECT_DATATYPE_*,默认 0(FLOAT64)。
770
786
 
771
787
  Returns:
File without changes