11# A part of NonVisual Desktop Access (NVDA)
2- # Copyright (C) 2021 NV Access Limited
2+ # Copyright (C) 2021-2022 NV Access Limited, Łukasz Golonka
33# This file is covered by the GNU General Public License.
44# See the file COPYING for more details.
55
6- from dataclasses import (
7- dataclass ,
8- field ,
9- )
10- from typing import Optional
11-
12- from comtypes import (
13- GUID ,
14- byref ,
15- )
16- import winVersion
17-
18-
196"""
207This module provides helpers and a common format to define UIA custom annotation types.
218The common custom annotation types are defined here.
3219GUID for the annotation type.
3320"""
3421
22+ import dataclasses
23+ from typing import (
24+ ClassVar ,
25+ Dict ,
26+ )
27+
28+ from comtypes import (
29+ GUID ,
30+ byref ,
31+ )
32+
33+ import winVersion
34+
3535
36- @dataclass
36+ @dataclasses . dataclass
3737class CustomAnnotationTypeInfo :
3838 """Holds information about a CustomAnnotationType
3939 This makes it easy to define custom annotation types to be loaded.
4040 """
4141 guid : GUID
42- id : int = field (init = False )
42+ _registeredAnnotations : ClassVar [Dict [GUID , int ]] = dict ()
43+
44+ def _registerCustomAnnotation (self ) -> int :
45+ """ Registers the annotation with a given GUID.
4346
44- def __post_init__ (self ) -> None :
45- """ The id field must be initialised at runtime.
4647 A GUID uniquely identifies a custom annotation, but the UIA system relies on integer IDs.
4748 Any application (clients or providers) can register a custom annotation type, subsequent applications
4849 will get the same id for a given GUID.
@@ -52,29 +53,30 @@ def __post_init__(self) -> None:
5253 """
5354 if winVersion .getWinVer () >= winVersion .WIN11 :
5455 import NVDAHelper
55- self . id = NVDAHelper .localLib .registerUIAAnnotationType (
56+ return NVDAHelper .localLib .registerUIAAnnotationType (
5657 byref (self .guid ),
5758 )
58- else :
59- self .id = 0
59+ return 0
60+
61+ @property
62+ def id (self ) -> int :
63+ """Return an ID for a given annotation registering it first if necessary.
64+
65+ Id's of all registered annotations are cached when requested for the first time
66+ to prevent unnecessary work by repeatedly interacting with UIA .
67+ """
68+ try :
69+ annotationId = self ._registeredAnnotations [self .guid ]
70+ except KeyError :
71+ annotationId = self ._registerCustomAnnotation ()
72+ self ._registeredAnnotations [self .guid ] = annotationId
73+ return annotationId
6074
6175
6276class CustomAnnotationTypesCommon :
6377 """UIA 'custom annotation types' common to all applications.
6478 Once registered, all subsequent registrations will return the same ID value.
65- This class should be used as a singleton via CustomAnnotationTypesCommon.get()
66- to prevent unnecessary work by repeatedly interacting with UIA.
6779 """
68- #: Singleton instance
69- _instance : "Optional[CustomAnnotationTypesCommon]" = None
70-
71- @classmethod
72- def get (cls ) -> "CustomAnnotationTypesCommon" :
73- """Get the singleton instance or initialise it.
74- """
75- if cls ._instance is None :
76- cls ._instance = cls ()
77- return cls ._instance
7880
7981 def __init__ (self ):
8082 # Registration of Custom annotation types used across multiple applications or frameworks should go here.
0 commit comments