
    lKjP                         d dl mZmZ d dlmZmZmZmZ d dlm	Z	m
Z
 d dlmZmZmZmZ d dlmZmZmZmZ d dlm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Zd dlZ ej@                  e!      Z" G d d	      Z#y)
    )BROWSER_BUNDLE_IDSEXCLUDED_BUNDLE_IDS)DesktopStateSizeWindowStatus)BoundingBoxTreeElementNode)Image	ImageDraw	ImageFont	ImageGrab)LiteralOptionalTupleUnion)TreeNc                      e Zd Zd ZdefdZ	 	 	 d6dededefdZ	 	 	 	 d7d	e	d
   de
e   de
eeef      de
eeef      def
dZ	 	 d8ded	e	d   dedeeef   fdZ	 	 	 d9dedede
e   de
e   def
dZ	 	 d:deeef   de	d   deddfdZ	 	 	 d;deeef   dede	d   d ed!eddfd"Z	 d<de
eeef      d#e	d$   d%e	d&   d'ede
e   f
d(Zdeeef   ddfd)Zdeeef   ddfd*Zd+eddfd,Zd-edefd.Zd/eddfd0Zde
e   fd1Zdee   fd2Z	 d=dedeej<                  edf   fd3Z 	 	 d>d4ee!   dededeej<                  edf   fd5Z"y)?Desktopc                 0    t               | _        d | _        y )N)r   treedesktop_state)selfs    j/Users/ahmed/devFolder/Ultron/claude-voice/.venv/lib/python3.12/site-packages/macos_mcp/desktop/service.py__init__zDesktop.__init__   s    F	!    returnc                 J    t        j                         \  }}t        ||      S )zIReturn the virtual screen size (all displays combined) in logical points.)widthheight)axGetScreenSizer   )r   r   r    s      r   get_screen_sizezDesktop.get_screen_size   s!    ((*v%//r   
use_visionas_bytesscalec                     | j                         }| j                         }| j                  j                  |      }|r| j	                  |j
                  ||      }nd }t        ||||      S )N)active_window)nodesr%   r&   )r(   windows
screenshot
tree_state)get_windowsget_foreground_windowr   	get_stateget_annotated_screenshotinteractive_nodesr   )r   r$   r%   r&   r*   r(   r,   r+   s           r   r/   zDesktop.get_state   s~     ""$224YY((}(E
66 22! 7 J J'!!	
 	
r   Nmode)launchresizemoveswitchname
window_locwindow_sizec                    |dk(  r&|syt        j                  |      }|rd| dS d| dS |dk(  rq|syt        j                  |      xs t        j                  |      }|sd| d	S t        j                  |j
                         t        j                  d
       d| dS |dk(  r]t        j                         }|r|j                  sy|j                  }|sy|j                  t        |d         t        |d                y|dk(  r]t        j                         }|r|j                  sy|j                  }|sy|j                  t        |d         t        |d                yd| S )z;Manage applications: launch, resize, move, or switch focus.r3   z*App name or bundle ID required for launch.z	Launched .zFailed to launch r6   z*App name or bundle ID required for switch.zApplication 'z' not found.g?zSwitched to r4   zNo frontmost window to resize.z%window_size required for resize mode.r      zWindow resized.r5   zNo frontmost window to move.z"window_loc required for move mode.zWindow moved.zUnknown mode: )r!   LaunchApplicationGetRunningApplicationByNameGetRunningApplicationByBundleIdActivateApplicationPIDtimesleepGetFrontmostApplication
MainWindowResizefloatMoveWindowTo)r   r2   r7   r8   r9   okappwins           r   rJ   zDesktop.app5   so    8C%%d+B*,YtfA&M4EdV12MM8C00 :33D9  &tfL99""377+JJsO!$q))8,,.Ccnn7..C>JJu[^,eKN.CD$6>,,.Ccnn5..C;U:a=15A3GH"v&&r   command)shell	osascripttimeoutc                 2    t        j                  |||      S )z'Execute a shell or AppleScript command.)r2   rO   )r!   ExecuteCommand)r   rL   r2   rO   s       r   execute_commandzDesktop.execute_commanda   s       tWEEr   messagetitlesubtitlesoundc                 p   ddl }dt        j                  |       dt        j                  |       }|r|dt        j                  |       z  }|r|dt        j                  |       z  }|j                  dd|gd	d	
      }|j                  dk(  rd| d| S d|j
                  j                          S )z!Send a macOS notification banner.r   Nzdisplay notification z with title z
 subtitle z sound name rN   z-eT)capture_outputtextzNotification sent: [z] zFailed to send notification: )
subprocessjsondumpsrun
returncodestderrstrip)r   rS   rT   rU   rV   rZ   scriptresults           r   notifyzDesktop.notifyj   s     	 $DJJw$7#8TZZPUEVDWX 	 
4::h#7"899FTZZ%6$788F$'4   
 !)%7)<<.v}}/B/B/D.EFFr   locbutton)leftrightmiddleclicksc                 &   |\  }}|dk(  rt        j                  ||       y|dk(  r3|dk(  rt        j                  ||       yt        j                  ||       y|dk(  rt        j                  ||       y|dk(  rt        j
                  ||       yy)z#Perform mouse click at coordinates.r   Nrf      rg   rh   )r!   MoveToDoubleClickClick
RightClickMiddleClick)r   rd   re   ri   xys         r   clickzDesktop.click   s     1Q;IIaOV{q!$AwMM!QxNN1a   r   rY   caret_position)startidleendclearpress_enterc                    |\  }}t        j                  ||       t        j                  ||       t        j                  d       |rUt        j
                  dd       t        j                  d       t        j
                  d       t        j                  d       |dk(  r,t        j
                  dd       t        j                  d       n0|d	k(  r+t        j
                  dd
       t        j                  d       t        j                  |       |r.t        j                  t         j                  j                         yy)z0Type text at coordinates. Clicks to focus first.g?rL   a皙?deleteru   rf   g{Gz?rw   rg   N)
r!   rl   rn   rB   rC   HotKeyTypeTextKeyPressKeyCodeReturn)r   rd   rY   rt   rx   ry   rq   rr   s           r   typezDesktop.type   s     1
		!Q
A

3IIi%JJtIIhJJtW$IIi(JJtu$IIi)JJt
DKK

))* r   scroll_type)
horizontalvertical	direction)updownrf   rg   wheel_timesc                    |r1t        j                  |d   |d          t        j                  d       |dv rdnd}t	        |      D ]  }|dk(  r6|dv r0|dk  rt        j
                  d      nt        j                  d       n8 y|d	v r0|dk  rt        j                  d      nt        j                  d       n y
t        j                  d        y)z0Scroll at coordinates or current mouse position.r   r<   r|   )r   rg   r   )r   r   z1Use direction 'up' or 'down' for vertical scroll.)rf   rg   z6Use direction 'left' or 'right' for horizontal scroll.N)	r!   rl   rB   rC   rangeWheelUp	WheelDown	WheelLeft
WheelRight)r   rd   r   r   r   mult_s          r   scrollzDesktop.scroll   s     IIc!fc!f%JJt!22q{#Aj(.%)AXBJJqM2<<?N 11'+axBLLOR]]15ESJJt $ r   c                 <    t        j                  |d   |d          y)z!Move mouse cursor to coordinates.r   r<   N)r!   rl   )r   rd   s     r   r5   zDesktop.move   s    
		#a&#a&!r   c                 t    t        j                         }t        j                  |d   |d   |d   |d          y)z1Drag from current position to target coordinates.r   r<   N)r!   GetCursorPosDragTo)r   rd   ru   s      r   dragzDesktop.drag   s0    !
		%(E!Hc!fc!f5r   shortcutc                     |j                  d      D cg c]   }|j                         j                         " }}t        j                  |  yc c}w )z-Execute keyboard shortcut (e.g. 'command+c').+N)splitr`   lowerr!   r~   )r   r   kkeyss       r   r   zDesktop.shortcut   s@    +3>>#+>?+>a	!+>?
		4 @s   %Aurlc                     	 ddi}t        j                  |d|      }|j                          ddlm}  ||j                  ddg	      S # t
        $ r}t        |      cY d
}~S d
}~ww xY w)zFetch URL content as markdown.z
User-AgentzuMozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36
   )rO   headersr   )markdownifyra   style)r`   N)requestsgetraise_for_statusr   rY   	Exceptionstr)r   r   r   rr   es         r   scrapezDesktop.scrape   si    		  VG S"g>A /qvvh-@AA 	q6M	s   AA
 
	A(
A#A(#A(durationc                 .    t        j                  |       y)z*Pause for the specified number of seconds.N)rB   rC   )r   r   s     r   waitzDesktop.wait   s    

8r   c                 \   d}t        j                  d       d }t        j                         }|r	 |j                  }|st        j                         }|st        j                         }d }|r	 ddlm	}  ||      }|t        j                  |      }|y d }	 |j                  }||j                  xs |}|j                  }	 t        |      }	||k7  r>t!        |j"                  xs ||t$        v |	t'        dddddd      |j                  |      S t!        dd	|	t'        dddddd      |j                  |      S |j                  t$        v }
|j(                  }|rt'        t+        |j,                        t+        |j.                        t+        |j0                        t+        |j2                        t+        |j4                        t+        |j6                              }nt'        dddddd      }|j                  }	 t        |      }	t!        |j"                  |
|	||j                  |j                        S # t
        $ r d }Y 
w xY w# t
        $ r d }Y w xY w# t
        $ r d }Y w xY w# t        $ r t        j                  }	Y w xY w# t        $ r t        j                  }	Y w xY w)
Nzcom.apple.finderr|   r   )ApplicationControl)pidrf   toprg   bottomr   r    r7   
is_browserstatusbounding_boxr   	bundle_idFinderF)rB   rC   r!   rD   rA   r   GetMenuBarOwningApplicationGetForegroundWindowPIDmacos_mcp.ax.controlsr   r?   rE   BundleIdentifierr   
ValueErrorACTIVEr   Namer   r	   BoundingRectangleintrf   r   rg   r   r   r    )r   FINDER_BUNDLE_IDr   	frontmostrJ   r   windowr   
status_strr   r   rectr   s                r   r.   zDesktop.get_foreground_window   s   -

4..0	mm 002C++-CD(S1 ;445EFC;	^^F >,,@0@IJ'
+ ,, .Y(,>>!!,!!AUV_`!a'   (aQaQR[\]GG#  ))-??
''&^M$**o4;;'$**o4;;'L 'AQq!L ZZ
	#J'F !%**
 	
O      	F	  ''T  	#]]F	#sY   H9 .I I I/ ?J 9IIIII,+I,/JJJ+*J+c                 ~   t        j                  d      }g }|D ]~  }|j                  xs d}|t        v r|j                  xs d}|j
                  }|t        v }|j                  }	 t        |      }	|	t        j                  t        j                  t        j                  fv rt        dddddd      }
n|j                  }|r|j                  }|rt        t        |j                         t        |j"                        t        |j$                        t        |j&                        t        |j(                        t        |j*                              }
n#t        dddddd      }
nt        dddddd      }
|j-                  t/        |||	|
||              |S # t        $ r t        j                  }	Y Gw xY w)u   
        Get list of user-facing application windows on the desktop.
        Uses the ax module's ApplicationControl API for all data.

        Returns:
            windows — list of Window objects
        Regular)policy r   r   r   )r!   GetRunningApplicationsr   r   r   rA   r   r   r   
WINDOWLESSHIDDEN	MINIMIZEDr	   rE   r   r   rf   r   rg   r   r   r    appendr   )r   appsr*   rJ   r   app_namer   r   r   r   bboxmain_windowr   s                r   r-   zDesktop.get_windowsE  s    ((	:C,,2I//xx~2H''C"&88J J+
+
 &--)9)96;L;LMM"q!1UVW!nn&88D*!$TYY #DHH"%djj/#&t{{#3"%djj/#&t{{#3   +!"1Aa  'AQq!D NN!)!!%'	S h O  +**+s   )FF<;F<c                     t        j                  d      }|r7t        j                         }|j	                  |d       |j                         S |S )z
        Capture a screenshot of the screen using Pillow ImageGrab.

        Args:
            as_bytes: If True, return PNG bytes.

        Returns:
            PIL Image, PNG bytes, or None on failure.
        T)all_screensPNGformat)r   grabioBytesIOsavegetvalue)r   r%   imagebufs       r   get_screenshotzDesktop.get_screenshot  sA     40**,CJJs5J)<<>!r   r)   c                    | j                         t        j                  d       ydt        j                  dz  z         }t        j
                  dz  z         }t        j                  d||fd      }|j                  f       t        j                  |      t        j                         d}D ]  }||d	<   ||d
   z  } rd   d   ndrt        d D              nddt        dt        dt        t            ffddt        dt        dt"        t        t        f   ffdrd   d   nt        j$                         }	t'        dt        d|	z              	 d}
t(        j*                  j-                  |
      sd}
t/        j0                  |
      t7               dt        dt8        ddffd}t;        |      D ]  \  }} |||        |dk  ru|dkD  rpt'        dt        |j                  |z              }t'        dt        |j
                  |z              }|j=                  ||ft        j>                  j@                        }|r7tC        jD                         }|jG                  |d       |jI                         S |S # t2        $ r t/        j4                         Y w xY w)a  
        Take a screenshot and annotate it with numbered bounding boxes for each
        interactive element. Captures the screenshot internally. Mirrors Windows-MCP.

        Args:
            nodes: List of TreeElementNode (interactive_nodes from tree state).
            as_bytes: If True, return PNG bytes; otherwise return PIL Image.

        Returns:
            Annotated PIL Image, PNG bytes, or None on failure.
        NzeScreenshot capture failed. Grant Screen Recording permission in System Settings > Privacy & Security.   g      ?RGB   r   r   )colorr   
pixel_leftpixel_widthlogical_leftc              3   &   K   | ]	  }|d      yw)logical_topN .0ds     r   	<genexpr>z3Desktop.get_annotated_screenshot.<locals>.<genexpr>  s     8-Q- -   lxlyr   c                     D ]:  }|d   | cxk  r|d   |d   z   k  sn |d   |cxk  r|d   |d   z   k  s6|c S  < y )Nr   logical_widthr   logical_heightr   )r   r   r   display_infoss      r   _find_displayz7Desktop.get_annotated_screenshot.<locals>._find_display  s`    "n%Ta.?!OBT.TT-(BW=1AAFVDW1WWH X # r   c                      | |      }|r8|d   t        | |d   z
  |d   z        z   }t        ||d   z
  |d   z        }||fS j                  t        t        d D              d      z  }t        | 	z
  |z        t        |
z
  |z        fS )Nr   r   r&   r   c              3   &   K   | ]	  }|d      yw)r   Nr   r   s     r   r   zNDesktop.get_annotated_screenshot.<locals>._logical_to_pixel.<locals>.<genexpr>  s     >1Ao&r   r<   )r   r   maxsum)r   r   r   pxpy	avg_scaler   r   imgvirtual_leftvirtual_tops         r   _logical_to_pixelz;Desktop.get_annotated_screenshot.<locals>._logical_to_pixel  s    b"%A|_sB>1B,Baj+P'QQ"q//1W:=>2v		C>>>% I \)Y67k!Y.:  r   r&         z#/System/Library/Fonts/Helvetica.ttcz,/System/Library/Fonts/Supplemental/Arial.ttflabelnodec                 f   |j                   }|j                  dk  s|j                  dk  ry |j                  |j                  |j                  |j                  f}|!v ry !j                  |       |j                  |j                  z   dz  }|j                  |j                  z   dz  } ||      }|r|d   }|d   }|d   }	|d   }
|t        |j                  |	z
  |z        z    z   }t        |j                  |
z
  |z         z   }|t        |j                  |	z
  |z        z    z   }t        |j                  |
z
  |z         z   }nT |j                  |j                        \  }} |j                  |j                        \  }}| z  }| z  }| z  }| z  }t        j                  |        t        j                  dd      t        j                  dd      t        j                  dd      f}j                  ||||g|d	       t        |       }	 j                  d
|      \  }}}}||z
  ||z
  }}||z
  dz
  }||z
  dz
  }| k  r|}||z   dz   }||z   dz   }j                  ||||g|       j#                  |dz   |dz   f|d       y # t        $ r t!        |      dz  }}Y ww xY w)Nr   rk   r&   r   r   r   2   r   )outliner   )r   r   )font      )fillr   )r  r  )r   r   r    rf   r   addrg   r   r   randomseedrandint	rectangler   textbboxr   lenrY   )"r  r  boxbox_keycxcyr   spldldtx1y1x2y2r   
label_textrf   r   rg   r   text_wtext_htag_x1tag_y1tag_x2tag_y2r   r  drawr  	font_sizepadding
seen_boxess"                              r   draw_annotationz9Desktop.get_annotated_screenshot.<locals>.draw_annotation  s   ##CyyA~qxx#))SZZ@G*$NN7# ((SYY&!+B''CJJ&!+Bb"%AgJ|_~&}%#sxx"}122W<#''B,!+,w6#syy2~233g=#**r/Q./'9*388SWW=B*399cjjABgggg KKr3'r3'r3'E NNBB+U!NDUJ@+/==RV=+W(c5&!&v|
 &[1_F&[1_Ff_q(Ff_q(FNNFFFF;%NHII!VaZ(*4o    @!$Z1!4i@s   #J J0/J0      ?r<   r   r   )%r   loggerwarningr   r   r    r   newpaster   Drawr!   GetPerDisplayInfominrG   r   dicttupleGetDPIScaler   ospathexistsr   truetyper   load_defaultsetr
   	enumerater4   
ResamplingBILINEARr   r   r   r   )r   r)   r%   r&   r   r    paddedpixel_left_accr   	dpi_scale	font_pathr2  ir  new_wnew_hr   r   r  r   r.  r  r/  r  r0  r1  r  r  s                    @@@@@@@@@@@r   r0   z Desktop.get_annotated_screenshot  s   " !!#;NNw CIIg-.SZZ#-/055&/IS7G,-~~f% ,,.A,AlOa..N  <I}Q'7a<IC8-88q 		e 	 	8D> 		% 	U 	uS#X 	 	 2?M!$W-BNNDT	CY/0		,=I77>>),J	%%i;D 69U
:	3 :	o :	$ :	 :	x !'GAtAt$ ( 3;5193v||e345E3v}}u456E]]E5>53C3C3L3LMF**,CKKEK*<<>![  	,))+D	,s   :9J( (K	K	)FFr3  )r3   NNN)rM   r   )NotificationNN)rf   r<   )rv   FF)r<   )F)Fr3  )#__name__
__module____qualname__r   r   r#   boolrG   r/   r   r   r   r   r   rJ   rR   rc   rs   r   r   r5   r   r   r   r   r   r.   listr-   r   r   bytesr   r
   r0   r   r   r   r   r      s=   "0 0 !	

 
 	
4 ?G"0415*':;*' sm*' U38_-	*'
 eCHo.*' 
*'^ /6	FF *+F 	F
 
sCxF $"&#GG G 3-	G
 }G 
G6 6<	!38_! 12! 	!
 
!2 ;A!+38_+ +   67	+
 + + 
+B eCHo& 56 89	
  
#4"c3h "D "6c3h 6D 6
  
# # S T W
x'7 W
r@T&\ @H  
u{{E4'	(. 	ZO$Z Z 	Z
 
u{{E4'	(Zr   r   )$macos_mcp.desktop.configr   r   macos_mcp.desktop.viewsr   r   r   r   macos_mcp.tree.viewsr	   r
   PILr   r   r   r   typingr   r   r   r   macos_mcp.tree.servicer   macos_mcp.axr!   r   loggingr  r[   r   r>  rB   	getLoggerrO  r4  r   r   r   r   <module>r^     sV    L F F = 6 6 2 2 '      	 	 			8	$b br   