§
    æ=¦jà1  ã                  óÄ   — U d Z ddlmZ ddlZddlZddlZddlZddlZddlm	Z	m
Z
mZ ddlZddlZddlZddlZddlZddlZddlmZmZ daded<   dd
„Z G d„ d¦  «        ZdS )u1  
Poe2VisualTool Item Hover Watcher (Passive Win32 Mouse & Clipboard Listener)
Theo dÃµi vá»‹ trÃ­ con trá»� chuá»™t thá»¥ Ä‘á»™ng á»Ÿ táº§n sá»‘ 40Hz (25ms) qua Win32 API.
Focus Interlock: Chá»‰ kÃ­ch hoáº¡t khi cá»­a sá»• game PathOfExile.exe (hoáº·c Poe2VisualTool.exe) Ä‘ang Active.
Hover Dwell Tracker: Khi chuá»™t Ä‘á»©ng yÃªn <= 5px trong >= 180ms:
  - Gá»­i xung Ctrl+C an toÃ n qua keybd_event.
  - Ä�á»�c clipboard thá»¥ Ä‘á»™ng qua win32clipboard.
  - PhÃ¢n tÃ­ch vÃ  gá»�i callback on_item_inspected(report, cursor_x, cursor_y).
  - Debounce báº±ng MD5 hash trÃ¡nh spam phÃ­m láº·p láº¡i vÃ´ nghÄ©a.
Mouse Move Trigger: Khi chuá»™t di chuyá»ƒn > 8px, gá»�i callback on_cursor_moved() Ä‘á»ƒ táº¯t tooltip tá»©c thÃ¬ (0ms).
100% Zero-Disk, Zero-Memory-Write, Zero-Ban risk.
Bá»‘i cáº£nh: 13/09/2026 (Rule 2)
é    )ÚannotationsN)ÚCallableÚOptionalÚTuple)ÚItemInspectionReportÚinspect_itemzOptional[int]Ú_global_default_deskÚreturnÚboolc                 óJ  — t           j        dk    rdS 	 ddl} | j        j        }|                     ddd¦  «        }|r|                     |¦  «         |                     dddd¦  «        }|r&|                     |¦  «         t          |¦  «        a
dS n# t          $ r Y nw xY wdS )	uZ   Ä�áº£m báº£o luá»“ng cháº¡y gáº¯n vÃ o interactive desktop 'default' cá»§a ngÆ°á»�i dÃ¹ng.ÚntFr   NÚWinSta0i   ÚDefaultT)ÚosÚnameÚctypesÚwindllÚuser32ÚOpenWindowStationWÚSetProcessWindowStationÚOpenDesktopWÚSetThreadDesktopÚintr	   Ú	Exception)r   r   ÚhwinstaÚhdesks       ú>c:\Projects\Poe2VisualTool\src\assistant\item_hover_watcher.pyÚattach_to_default_desktopr   $   sÏ   € å	„w�$‚€ØˆuðØˆˆˆØ”Ô%ˆØ×+Ò+¨I°u¸jÑIÔIˆØð 	4Ø×*Ò*¨7Ñ3Ô3Ð3Ø×#Ò# I¨q°%¸ÑDÔDˆØð 	Ø×#Ò# EÑ*Ô*Ð*Ý#& u¡:¤:Ð Ø�4ð	øõ ð ð ð Øˆðøøøàˆ5s   ”A<B Â
B ÂB c                  óˆ   — e Zd ZdZdZ	 	 	 	 	 	 	 d)d*d„Zd+d„Zd+d„Zed,d„¦   «         Z	d-d„Z
d,d„Zd+d„Zd.d/d!„Zd0d'„Zd+d(„ZdS )1ÚItemHoverWatcheruÃ   
    Bá»™ giÃ¡m sÃ¡t di chuá»™t vÃ  bÃ³c tÃ¡ch dá»¯ liá»‡u váº­t pháº©m thá»¥ Ä‘á»™ng trÃªn Windows.
    Ä�áº£m báº£o an toÃ n tÃ i khoáº£n tuyá»‡t Ä‘á»‘i vá»›i Focus Interlock vÃ  Debounce.
    )zPathOfExile.exezPathOfExileSteam.exezPathOfExile_x64.exezPathOfExile_x64Steam.exezPathOfExileKG.exezPathOfExile_x64KG.exezPoe2VisualTool.exezAutoPOE2_VisualTool.exeNç     €f@çš™™™™™™?TFÚon_item_inspectedú:Optional[Callable[[ItemInspectionReport, int, int], None]]Úon_cursor_movedúOptional[Callable[[], None]]Údwell_time_msÚfloatÚpoll_interval_sÚallowed_processesúOptional[Tuple[str, ...]]Úenable_focus_interlockr   Úsimulate_keysc                ó$  — t          ¦   «          || _        || _        || _        || _        |p| j        | _        || _        || _        d| _	        d | _
        t          j        ¦   «         | _        d| _        d| _        d | _        d | _        d | _        d S )NFÚ )r   r#   r%   r'   r)   ÚDEFAULT_ALLOWED_PROCESSESr*   r,   r-   Ú_runningÚ_threadÚ	threadingÚLockÚ_lockÚtooltip_activeÚlast_inspected_hashÚ_mock_cursor_posÚ_mock_clipboard_textÚ_mock_is_focused)Úselfr#   r%   r'   r)   r*   r,   r-   s           r   Ú__init__zItemHoverWatcher.__init__J   s�   € õ 	"Ñ#Ô#Ð#Ø!2ˆÔØ.ˆÔØ*ˆÔØ.ˆÔØ!2Ð!T°dÔ6TˆÔØ&<ˆÔ#Ø*ˆÔàˆŒØ37ˆŒÝ”^Ñ%Ô%ˆŒ
ð $ˆÔØ(*ˆÔ Ø;?ˆÔØ37ˆÔ!Ø04ˆÔÐÐó    r
   ÚNonec                ó  — t          ¦   «          | j        5  | j        r	 ddd¦  «         dS d| _        t          j        | j        dd¬¦  «        | _        | j                             ¦   «          ddd¦  «         dS # 1 swxY w Y   dS )u0   Khá»Ÿi Ä‘á»™ng luá»“ng giÃ¡m sÃ¡t thá»¥ Ä‘á»™ng.NTÚItemHoverWatcherWorker)ÚtargetÚdaemonr   )r   r5   r1   r3   ÚThreadÚ_worker_loopr2   Ústart©r;   s    r   rE   zItemHoverWatcher.starth   sé   € å!Ñ#Ô#Ð#ØŒZð 	!ð 	!ØŒ}ð Øð	!ð 	!ð 	!ñ 	!ô 	!ð 	!ð 	!ð 	!ð !ˆDŒMÝ$Ô+°4Ô3DÈTÐXpÐqÑqÔqˆDŒLØŒL×ÒÑ Ô Ð ð	!ð 	!ð 	!ñ 	!ô 	!ð 	!ð 	!ð 	!ð 	!ð 	!ð 	!ð 	!øøøð 	!ð 	!ð 	!ð 	!ð 	!ð 	!s   –	A:¬AA:Á:A>ÂA>c                óÞ   — | j         5  d| _        ddd¦  «         n# 1 swxY w Y   | j        r=| j                             ¦   «         r&| j                             d¬¦  «         d| _        dS dS dS )u   Dá»«ng luá»“ng giÃ¡m sÃ¡t.FNg      ð?)Útimeout)r5   r1   r2   Úis_aliveÚjoinrF   s    r   ÚstopzItemHoverWatcher.stopr   s½   € àŒZð 	"ð 	"Ø!ˆDŒMð	"ð 	"ð 	"ñ 	"ô 	"ð 	"ð 	"ð 	"ð 	"ð 	"ð 	"øøøð 	"ð 	"ð 	"ð 	"àŒ<ð 	 ˜DœL×1Ò1Ñ3Ô3ð 	 ØŒL×Ò cÐÑ*Ô*Ð*ØˆDŒLˆLˆLð	 ð 	 ð 	 ð 	 s   ˆœ £ c                ó   — | j         S ©N)r1   rF   s    r   Ú
is_runningzItemHoverWatcher.is_runningz   s
   € àŒ}Ðr=   úTuple[int, int]c                óh   — | j         �| j         S 	 t          j        ¦   «         S # t          $ r Y dS w xY w)uI   Láº¥y tá»�a Ä‘á»™ chuá»™t hiá»‡n táº¡i (há»— trá»£ mock khi cháº¡y test).N)r   r   )r8   Úwin32guiÚGetCursorPosr   rF   s    r   Úget_cursor_poszItemHoverWatcher.get_cursor_pos~   sJ   € àÔ Ð,ØÔ(Ð(ð	ÝÔ(Ñ*Ô*Ð*øÝð 	ð 	ð 	Ø�6�6ð	øøøs   �# £
1°1c                óö  ‡	— | j         �| j         S | j        sdS 	 t          j        ¦   «         }|sdS t          j        |¦  «        pd}t          j        |¦  «        pd}d|                     ¦   «         v rdS d|                     ¦   «         v rdS | j        D ]C}|                     dd¦  «        }|                     ¦   «         |                     ¦   «         v r dS ŒDt          j
        |¦  «        \  }}|dk    rdS |t          j        ¦   «         k    rdS t          j        |¦  «        }|                     ¦   «                              ¦   «         Š	t!          ˆ	fd	„| j        D ¦   «         ¦  «        S # t"          $ r Y dS w xY w)
uP   Focus Interlock: Kiá»ƒm tra cá»­a sá»• foreground cÃ³ pháº£i client POE2 khÃ´ng.NTFr/   Úpoezpath of exilez.exer   c              3  óD   •K  — | ]}|                      ¦   «         ‰v V — Œd S rM   )Úlower)Ú.0ÚpÚ	proc_names     €r   ú	<genexpr>z:ItemHoverWatcher.is_game_window_focused.<locals>.<genexpr>©   s0   øè è € ÐNÐN°!�q—w’w‘y”y IÐ-ÐNÐNÐNÐNÐNÐNr=   )r:   r,   rQ   ÚGetForegroundWindowÚGetWindowTextÚGetClassNamerW   r*   ÚreplaceÚwin32processÚGetWindowThreadProcessIdr   ÚgetpidÚpsutilÚProcessr   Úanyr   )
r;   ÚhwndÚtitleÚcls_namerY   Úname_no_extÚ_ÚpidÚprocrZ   s
            @r   Úis_game_window_focusedz'ItemHoverWatcher.is_game_window_focused‡   s�  ø€ àÔ Ð,ØÔ(Ð(ØÔ*ð 	Ø�4ð	ÝÔ/Ñ1Ô1ˆDØð Ø�uõ Ô*¨4Ñ0Ô0Ð6°BˆEÝÔ,¨TÑ2Ô2Ð8°bˆHØ˜ŸšÑ(Ô(Ð(Ð(Ø�tØ %§+¢+¡-¤-Ð/Ð/Ø�tØÔ+ð  ð  �ØŸiši¨°Ñ3Ô3�Ø×$Ò$Ñ&Ô&¨%¯+ª+©-¬-Ð7Ð7Ø˜4˜4ð 8õ "Ô:¸4Ñ@Ô@‰FˆAˆsØ�aŠxˆxØ�uà•b”i‘k”kÒ!Ð!Ø�tå”> #Ñ&Ô&ˆDØŸ	š	™œ×)Ò)Ñ+Ô+ˆIÝÐNÐNÐNÐN°tÔ7MÐNÑNÔNÑNÔNÐNøÝð 	ð 	ð 	Ø�5�5ð	øøøs7   šE* ±AE* Á5E* ÂAE* ÃE* Ã7E* ÄAE* Å*
E8Å7E8c                ó   — | j         rdS 	 t          j        t          j        ddd¦  «         t          j        t          d¦  «        ddd¦  «         t          j        d¦  «         t          j        t          d¦  «        dt          j        d¦  «         t          j        t          j        dt          j        d¦  «         dS # t          $ r Y dS w xY w)u5   Gá»­i tá»• há»£p phÃ­m Ctrl+C an toÃ n qua Win32 API.Nr   ÚCg¸…ëQ¸Ž?)
r-   Úwin32apiÚkeybd_eventÚwin32conÚ
VK_CONTROLÚordÚtimeÚsleepÚKEYEVENTF_KEYUPr   rF   s    r   Úsend_ctrl_czItemHoverWatcher.send_ctrl_c­   sÄ   € àÔð 	ØˆFð	ÝÔ ¥Ô!4°a¸¸AÑ>Ô>Ð>ÝÔ ¥ S¡¤¨1¨a°Ñ3Ô3Ð3ÝŒJ�uÑÔÐÝÔ ¥ S¡¤¨1­hÔ.FÈÑJÔJÐJÝÔ ¥Ô!4°a½Ô9QÐSTÑUÔUÐUÐUÐUøÝð 	ð 	ð 	ØˆDˆDð	øøøs   ‹B2B? Â?
CÃCçš™™™™™©?Ú	timeout_sÚstrc                óR  — | j         �| j         S t          j        ¦   «         }t          j        ¦   «         |z
  |k     �rj	 t          j        ¦   «          	 t          j        t          j        ¦  «        r6t          j        t          j        ¦  «        }|pd	 t          j	        ¦   «          S t          j        t          j
        ¦  «        rut          j        t          j
        ¦  «        }t          |t          ¦  «        r*|                     dd¬¦  «        t          j	        ¦   «          S |pd	 t          j	        ¦   «          S 	 t          j	        ¦   «          n# t          j	        ¦   «          w xY wdS # t          $ r t          j        d¦  «         Y nw xY wt          j        ¦   «         |z
  |k     �°jdS )u=   Ä�á»�c ná»™i dung vÄƒn báº£n tá»« Windows Clipboard an toÃ n.Nr/   úutf-8Úignore©Úerrorsg{®Gázt?)r9   ru   Úperf_counterÚwin32clipboardÚOpenClipboardÚIsClipboardFormatAvailablerr   ÚCF_UNICODETEXTÚGetClipboardDataÚCloseClipboardÚCF_TEXTÚ
isinstanceÚbytesÚdecoder   rv   )r;   rz   Ústart_tÚdatas       r   Úread_clipboard_textz$ItemHoverWatcher.read_clipboard_text»   s¤  € àÔ$Ð0ØÔ,Ð,åÔ#Ñ%Ô%ˆÝÔÑ!Ô! GÑ+¨iÒ7Ñ7ð"ÝÔ,Ñ.Ô.Ð.ð
4Ý%Ô@ÅÔAXÑYÔYð *Ý-Ô>½xÔ?VÑWÔW˜Ø#˜z rÐ)õ #Ô1Ñ3Ô3Ð3Ð3õ (ÔBÅ8ÔCSÑTÔTð *Ý-Ô>½xÔ?OÑPÔP˜Ý% d­EÑ2Ô2ð IØ#'§;¢;¨w¸x ;Ñ#HÔ#Hõ #Ô1Ñ3Ô3Ð3Ð3ð  $˜z rÐ)å"Ô1Ñ3Ô3Ð3Ð3ð*õ #Ô1Ñ3Ô3Ð3Ð3ø•NÔ1Ñ3Ô3Ð3Ð3øøøØ�røÝð "ð "ð "Ý”
˜5Ñ!Ô!Ð!Ð!Ð!ð"øøøõ ÔÑ!Ô! GÑ+¨iÒ7Ñ7ð" ˆrsH   ¾E( Á?E ÂE( Â&A'E ÄE( Ä!E Ä%E( Ä:E( ÅE#Å#E( Å(F	ÆF	Úcur_xr   Úcur_yÚstateÚdictc                ó˜  — |                      d¦  «        }|                      d¦  «        }|                      dd¦  «        }|                      dd¦  «        }|�|€||f|d<   ||f|d<   d|d<   d|d<   dS t          j        ||d         z
  ||d	         z
  ¦  «        }t          j        ||d         z
  ||d	         z
  ¦  «        }	|	d
k    rN| j        r4d| _        | j        r&	 |                      ¦   «          n# t
          $ r Y nw xY wd|d<   d|d<   ||f|d<   �n,|dk    �r|| j        dz  z  }||d<   || j        k    rö|sôd|d<   |                      ¦   «         rÛ|  	                    ¦   «          t          j        d¦  «         |                      ¦   «         }
|
r�d|
v sd|
v r•t          j        |
                     dd¬¦  «        ¦  «                             ¦   «         }|| j        k    rO|| _        t%          |
¦  «        }|r7d| _        | j        r)	 |                      |||¦  «         n"# t
          $ r Y nw xY wnd|d<   d|d<   ||f|d<   ||f|d<   dS )uµ   
        Xá»­ lÃ½ 1 nhá»‹p thá»�i gian cá»§a Hover Dwell Tracker.
        TÃ¡ch biá»‡t thÃ nh hÃ m riÃªng Ä‘á»ƒ cÃ³ thá»ƒ test Ä‘Æ¡n vá»‹ xÃ¡c Ä‘á»‹nh (deterministic test).
        Úlast_posÚ
anchor_posÚdwell_accum_msç        Úhas_triggeredFNr   é   g       @g      @g     @�@Tg{®Gáz”?úItem Class:úRarity:r}   r~   r   )ÚgetÚmathÚhypotr6   r%   r   r)   r'   rm   rx   ru   rv   rŽ   ÚhashlibÚmd5ÚencodeÚ	hexdigestr7   r   r#   )r;   r�   r�   r‘   r”   r•   r–   r˜   Ú	step_distÚanchor_distÚtextÚ	text_hashÚreports                r   Úprocess_tickzItemHoverWatcher.process_tickÔ   sî  € ð —9’9˜ZÑ(Ô(ˆØ—Y’Y˜|Ñ,Ô,ˆ
ØŸšÐ#3°SÑ9Ô9ˆØŸ	š	 /°5Ñ9Ô9ˆàÐ˜zÐ1Ø!&¨ ˆE�*ÑØ#(¨% .ˆE�,ÑØ&)ˆEÐ"Ñ#Ø%*ˆE�/Ñ"ØˆFå”J˜u x°¤{Ñ2°E¸HÀQ¼KÑ4GÑHÔHˆ	Ý”j ¨°A¬Ñ!6¸À
È1ÄÑ8MÑNÔNˆð ˜ÒÐØÔ"ð Ø&+�Ô#ØÔ'ð ðØ×,Ò,Ñ.Ô.Ð.Ð.øÝ$ð ð ð Ø˜ðøøøà&)ˆEÐ"Ñ#Ø%*ˆE�/Ñ"Ø#(¨% .ˆE�,ÑÑà˜#ÒÑà˜dÔ2°VÑ;Ñ;ˆNØ&4ˆEÐ"Ñ#à Ô!3Ò3Ð3¸MÐ3Ø)-��oÑ&ð ×.Ò.Ñ0Ô0ð -Ø×$Ò$Ñ&Ô&Ð&Ý”J˜tÑ$Ô$Ð$Ø×3Ò3Ñ5Ô5�Dàð - °$Ð!6Ð!6¸)ÀtÐ:KÐ:KÝ$+¤K°·²¸GÈH°Ñ0UÔ0UÑ$VÔ$V×$`Ò$`Ñ$bÔ$b˜	ð %¨Ô(@Ò@Ð@Ø7@˜DÔ4Ý%1°$Ñ%7Ô%7˜FØ%ð -Ø6: Ô 3Ø#'Ô#9ð !-ð%-Ø(,×(>Ò(>¸vÀuÈeÑ(TÔ(TÐ(TÐ(TøÝ+4ð %-ð %-ð %-Ø(,¨ð%-øøøøð '*ˆEÐ"Ñ#Ø%*ˆE�/Ñ"Ø#(¨% .ˆE�,Ñà" E˜NˆˆjÑÐÐs$   ÃC4 Ã4
DÄ DÈ	H! È!
H.È-H.c                ó.  — t          ¦   «          ddddddœ}	 t          j        ¦   «         |d<   n# t          $ r Y nw xY w| j        �rN|                      ¦   «         \  }}|                      |||¦  «         	 t          j        ¦   «         }||d         k    rÌ||d<   |                      ¦   «         r³|                      ¦   «         }|r�d|v sd|v r•t          j
        |                     d	d
¬¦  «        ¦  «                             ¦   «         }|| j        k    rO|| _        t          |¦  «        }|r7d| _        | j        r)	 |                      |||¦  «         n# t          $ r Y nw xY wn# t          $ r Y nw xY wt#          j        | j        ¦  «         | j        �°LdS dS )u-   VÃ²ng láº·p ná»�n polling chuá»™t má»—i 25ms.Nr—   Fr   )r”   r•   r–   r˜   Úlast_clip_seqrª   rš   r›   r}   r~   r   T)r   r‚   ÚGetClipboardSequenceNumberr   r1   rS   r¨   rm   rŽ   rŸ   r    r¡   r¢   r7   r   r6   r#   ru   rv   r)   )r;   r‘   r�   r�   Úcur_seqr¥   r¦   r§   s           r   rD   zItemHoverWatcher._worker_loop  s  € å!Ñ#Ô#Ð#àØØ!Ø"Øð
ð 
ˆð	Ý%3Ô%NÑ%PÔ%PˆE�/Ñ"Ð"øÝð 	ð 	ð 	ØˆDð	øøøð Œmñ 	-Ø×.Ò.Ñ0Ô0‰LˆE�5Ø×Ò˜e U¨EÑ2Ô2Ð2ðÝ(ÔCÑEÔE�Ø˜e OÔ4Ò4Ð4Ø-4�E˜/Ñ*Ø×2Ò2Ñ4Ô4ð 1Ø#×7Ò7Ñ9Ô9˜Øð 1 ]°dÐ%:Ð%:¸iÈ4Ð>OÐ>OÝ(/¬°D·K²KÀÐPX°KÑ4YÔ4YÑ(ZÔ(Z×(dÒ(dÑ(fÔ(f˜IØ(¨DÔ,DÒDÐDØ;D Ô 8Ý)5°dÑ);Ô); Ø#)ð !1Ø:> DÔ$7Ø'+Ô'=ð %1ð)1Ø,0×,BÒ,BÀ6È5ÐRWÑ,XÔ,XÐ,XÐ,XøÝ/8ð )1ð )1ð )1Ø,0¨Dð)1øøøøøåð ð ð Ø�ðøøøõ ŒJ�tÔ+Ñ,Ô,Ð,ð5 Œmñ 	-ð 	-ð 	-ð 	-ð 	-sC   ˜/ ¯
<»<Á6CE" Ä9E ÅE" Å
EÅE" ÅEÅE" Å"
E/Å.E/)NNr!   r"   NTF)r#   r$   r%   r&   r'   r(   r)   r(   r*   r+   r,   r   r-   r   )r
   r>   ©r
   r   )r
   rO   )ry   )rz   r(   r
   r{   )r�   r   r�   r   r‘   r’   r
   r>   )Ú__name__Ú
__module__Ú__qualname__Ú__doc__r0   r<   rE   rK   ÚpropertyrN   rS   rm   rx   rŽ   r¨   rD   © r=   r   r    r    9   s#  € € € € € ðð ð
	!Ðð Y]Ø8<Ø$Ø!&Ø7;Ø'+Ø#ð5ð 5ð 5ð 5ð 5ð<!ð !ð !ð !ð ð  ð  ð  ð ðð ð ñ „Xððð ð ð ð$ð $ð $ð $ðLð ð ð ðð ð ð ð ð2H+ð H+ð H+ð H+ðT)-ð )-ð )-ð )-ð )-ð )-r=   r    r­   )r±   Ú
__future__r   rŸ   r�   r   r3   ru   Útypingr   r   r   rc   rp   r‚   rr   rQ   r`   Úsrc.assistant.item_inspectorr   r   r	   Ú__annotations__r   r    r³   r=   r   ú<module>r¸      s,  ððð ð ð #Ð "Ð "Ð "Ð "Ð "à €€€Ø €€€Ø 	€	€	€	Ø Ð Ð Ð Ø €€€Ø ,Ð ,Ð ,Ð ,Ð ,Ð ,Ð ,Ð ,Ð ,Ð ,à €€€Ø €€€Ø Ð Ð Ð Ø €€€Ø €€€Ø Ð Ð Ð à KÐ KÐ KÐ KÐ KÐ KÐ KÐ Kà&*Ð Ð *Ð *Ð *Ñ *ðð ð ð ð*N-ð N-ð N-ð N-ð N-ñ N-ô N-ð N-ð N-ð N-r=   