windows - reales - Ventana mover y cambiar el tamaño de API en OS X
libro de android studio en español pdf (2)
Estoy intentando encontrar API documentadas (o indocumentadas, si es mi única opción) en OS X para consultar una lista de ventanas desde el servidor de Windows y luego hacer que las ventanas se muevan y cambien de tamaño. ¿Alguien puede señalarme en la dirección correcta? Supongo que comenzaría con algo como FindWindowEx y MoveWindow bajo Win32.
Tenga en cuenta que quiero hacer esto desde un proceso externo: no estoy preguntando cómo controlar el tamaño y la posición de la ventana de mi propia aplicación.
Estoy de acuerdo en que la accesibilidad es la mejor manera de avanzar. Pero si quieres algo rápido y sucio, AppleScript también funcionará.
Use la API de accesibilidad. Usando esta API puede conectarse a un proceso, obtener una lista de ventanas (en realidad una matriz), obtener las posiciones y tamaños de cada ventana y también cambiar las propiedades de la ventana si lo desea.
Sin embargo, una aplicación solo puede usar esta API si el usuario ha habilitado el acceso para dispositivos de asistencia en sus preferencias (Preferencias del Sistema -> Acceso Universal), en cuyo caso todas las aplicaciones pueden usar esta API, o si su aplicación es una aplicación auxiliar confiable (cuando es de confianza, puede usar la API, incluso si esta opción no está marcada). La API de accesibilidad en sí misma ofrece las funciones necesarias para hacer que su aplicación sea confiable: básicamente, debe convertirse en usuario root (utilizando servicios de seguridad para solicitar permisos de raíz del usuario) y luego marcar su proceso como de confianza. Una vez que su aplicación ha sido marcada como confiable, debe reiniciarse ya que el estado de confianza solo se verifica durante el inicio y no puede cambiar mientras se ejecuta la aplicación. El estado de confianza es permanente, a menos que el usuario mueva la aplicación a otra parte o el hash de los cambios binarios de la aplicación (por ejemplo, después de una actualización). Si el usuario tiene dispositivos de asistencia habilitados en sus preferencias, todas las aplicaciones se tratan como si fuesen confiables. Usualmente su aplicación verificará si esta opción está habilitada, si es así, continúe y haga sus cosas. Si no, verificará si ya es de confianza, si lo es, de nuevo solo haz tus cosas. De lo contrario, trate de hacerse de confianza y luego reinicie la aplicación a menos que el usuario haya rechazado la autorización de la raíz. La API ofrece todas las funciones necesarias para verificar todo esto.
Existen funciones privadas para hacer lo mismo utilizando el administrador de ventanas de Mac OS, pero la única ventaja que le compraría es que no necesita ser una aplicación de accesibilidad confiable (que es una operación única en el primer lanzamiento en la mayoría de los casos) . Las desventajas son que esta API puede cambiar en cualquier momento (ya ha cambiado en el pasado), está todo indocumentado y las funciones solo se conocen mediante ingeniería inversa. Sin embargo, la Accesibilidad es pública, está documentada y no ha cambiado mucho desde la primera versión de OS X que la introdujo (algunas funciones nuevas se agregaron en 10.4 y nuevamente en 10.5, pero no mucho más ha cambiado).
Aquí hay un ejemplo de código. Esperará 5 segundos, por lo que puede cambiar a una ventana diferente antes de que haga cualquier otra cosa (de lo contrario, siempre funcionará con la ventana del terminal, algo aburrido para las pruebas). Luego obtendrá el proceso más frontal, la ventana más frontal de este proceso, imprima su posición y tamaño, y finalmente muévalo 25 píxeles hacia la derecha. Lo compila en una línea de comandos como esa (suponiendo que se llame test.c)
gcc -framework Carbon -o test test.c
Tenga en cuenta que no realizo ninguna comprobación de errores en el código por simplicidad (hay varios lugares que podrían hacer que el programa falle si algo sale mal y ciertas cosas pueden / pueden salir mal). Aquí está el código:
/* Carbon includes everything necessary for Accessibilty API */
#include <Carbon/Carbon.h>
static bool amIAuthorized ()
{
if (AXAPIEnabled() != 0) {
/* Yehaa, all apps are authorized */
return true;
}
/* Bummer, it''s not activated, maybe we are trusted */
if (AXIsProcessTrusted() != 0) {
/* Good news, we are already trusted */
return true;
}
/* Crap, we are not trusted...
* correct behavior would now be to become a root process using
* authorization services and then call AXMakeProcessTrusted() to make
* ourselves trusted, then restart... I''ll skip this here for
* simplicity.
*/
return false;
}
static AXUIElementRef getFrontMostApp ()
{
pid_t pid;
ProcessSerialNumber psn;
GetFrontProcess(&psn);
GetProcessPID(&psn, &pid);
return AXUIElementCreateApplication(pid);
}
int main (
int argc,
char ** argv
) {
int i;
AXValueRef temp;
CGSize windowSize;
CGPoint windowPosition;
CFStringRef windowTitle;
AXUIElementRef frontMostApp;
AXUIElementRef frontMostWindow;
if (!amIAuthorized()) {
printf("Can''t use accessibility API!/n");
return 1;
}
/* Give the user 5 seconds to switch to another window, otherwise
* only the terminal window will be used
*/
for (i = 0; i < 5; i++) {
sleep(1);
printf("%d", i + 1);
if (i < 4) {
printf("...");
fflush(stdout);
} else {
printf("/n");
}
}
/* Here we go. Find out which process is front-most */
frontMostApp = getFrontMostApp();
/* Get the front most window. We could also get an array of all windows
* of this process and ask each window if it is front most, but that is
* quite inefficient if we only need the front most window.
*/
AXUIElementCopyAttributeValue(
frontMostApp, kAXFocusedWindowAttribute, (CFTypeRef *)&frontMostWindow
);
/* Get the title of the window */
AXUIElementCopyAttributeValue(
frontMostWindow, kAXTitleAttribute, (CFTypeRef *)&windowTitle
);
/* Get the window size and position */
AXUIElementCopyAttributeValue(
frontMostWindow, kAXSizeAttribute, (CFTypeRef *)&temp
);
AXValueGetValue(temp, kAXValueCGSizeType, &windowSize);
CFRelease(temp);
AXUIElementCopyAttributeValue(
frontMostWindow, kAXPositionAttribute, (CFTypeRef *)&temp
);
AXValueGetValue(temp, kAXValueCGPointType, &windowPosition);
CFRelease(temp);
/* Print everything */
printf("/n");
CFShow(windowTitle);
printf(
"Window is at (%f, %f) and has dimension of (%f, %f)/n",
windowPosition.x,
windowPosition.y,
windowSize.width,
windowSize.height
);
/* Move the window to the right by 25 pixels */
windowPosition.x += 25;
temp = AXValueCreate(kAXValueCGPointType, &windowPosition);
AXUIElementSetAttributeValue(frontMostWindow, kAXPositionAttribute, temp);
CFRelease(temp);
/* Clean up */
CFRelease(frontMostWindow);
CFRelease(frontMostApp);
return 0;
}
Sine Ben preguntó cómo se obtiene una lista de todas las ventanas en los comentarios, así es cómo:
En lugar de "kAXFocusedWindowAttribute", utiliza "kAXWindowsAttribute" para la función AXUIElementCopyAttributeValue. El resultado entonces no es AXUIElementRef, sino un CFArray de elementos AXUIElementRef, uno para cada ventana de esta aplicación.