You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
206 lines
5.0 KiB
206 lines
5.0 KiB
1 year ago
|
/*
|
||
|
* For each focus/selection change, it prints the following for each
|
||
|
* object getting the focus/selection:
|
||
|
* (appname, name, rolename, [state-set])
|
||
|
*
|
||
|
* You can specify if you want to filter by application. Use --help
|
||
|
* for more information.
|
||
|
*/
|
||
|
|
||
|
#include <atspi/atspi.h>
|
||
|
#include <atspi/atspi-accessible.h>
|
||
|
#include <speech-dispatcher/libspeechd.h>
|
||
|
#include <stdlib.h>
|
||
|
#include <unistd.h>
|
||
|
#include <string.h>
|
||
|
|
||
|
gchar *filter_name = NULL;
|
||
|
SPDConnection *spd_conn = NULL;
|
||
|
|
||
|
const static gchar*
|
||
|
atspi_state_get_name(gint state)
|
||
|
{
|
||
|
GTypeClass *type_class;
|
||
|
GEnumValue *value;
|
||
|
|
||
|
type_class = g_type_class_ref(ATSPI_TYPE_STATE_TYPE);
|
||
|
g_return_val_if_fail(G_IS_ENUM_CLASS (type_class), "");
|
||
|
|
||
|
value = g_enum_get_value(G_ENUM_CLASS (type_class), state);
|
||
|
|
||
|
return value->value_nick;
|
||
|
}
|
||
|
|
||
|
static gchar*
|
||
|
get_state_set(AtspiAccessible *accessible)
|
||
|
{
|
||
|
AtspiStateSet *state_set = atspi_accessible_get_state_set(accessible);
|
||
|
GArray *states = atspi_state_set_get_states(state_set);
|
||
|
gchar *result = g_strdup_printf("[");
|
||
|
gchar *aux = NULL;
|
||
|
gint i;
|
||
|
AtspiStateType state;
|
||
|
|
||
|
for(i = 0; i < states->len; i++) {
|
||
|
state = g_array_index(states, gint, i);
|
||
|
|
||
|
aux = result;
|
||
|
if(i < states->len -1)
|
||
|
result = g_strdup_printf("%s%s,", aux, atspi_state_get_name(state));
|
||
|
else
|
||
|
result = g_strdup_printf("%s%s", aux, atspi_state_get_name(state));
|
||
|
g_free(aux);
|
||
|
}
|
||
|
|
||
|
aux = result;
|
||
|
result = g_strconcat(aux, "]", NULL);
|
||
|
g_free(aux);
|
||
|
|
||
|
g_array_free(states, TRUE);
|
||
|
g_object_unref(state_set);
|
||
|
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
static gchar*
|
||
|
get_label(AtspiAccessible *accessible)
|
||
|
{
|
||
|
GArray *relations;
|
||
|
AtspiRelation *relation;
|
||
|
gint i;
|
||
|
gchar *result = "";
|
||
|
|
||
|
relations = atspi_accessible_get_relation_set(accessible, NULL);
|
||
|
if(relations == NULL) {
|
||
|
return "";
|
||
|
}
|
||
|
|
||
|
for(i = 0; i < relations->len; i++) {
|
||
|
relation = g_array_index(relations, AtspiRelation*, i);
|
||
|
|
||
|
if(atspi_relation_get_relation_type (relation) == ATSPI_RELATION_LABELLED_BY) {
|
||
|
result = atspi_accessible_get_name(atspi_relation_get_target (relation, 0), NULL);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if(relations != NULL)
|
||
|
g_array_free(relations, TRUE);
|
||
|
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
print_info(AtspiAccessible *accessible,
|
||
|
gchar *app_name)
|
||
|
{
|
||
|
AtspiText *text = atspi_accessible_get_text_iface(accessible);
|
||
|
gchar *name = "NULL";
|
||
|
gchar *role_name = "NULL";
|
||
|
gchar *state_set = NULL;
|
||
|
gint length_of_string;
|
||
|
GError **error = NULL;
|
||
|
|
||
|
if(accessible != NULL) {
|
||
|
name = atspi_accessible_get_name(accessible, NULL);
|
||
|
if((name == NULL) || (g_strcmp0(name, "") == 0)) {
|
||
|
name = get_label(accessible);
|
||
|
if((name == NULL) || (g_strcmp0(name, "") == 0)) {
|
||
|
length_of_string = atspi_text_get_character_count(text, error);
|
||
|
name = atspi_text_get_text(text, 0, length_of_string, error);
|
||
|
}
|
||
|
}
|
||
|
role_name = atspi_accessible_get_role_name(accessible, NULL);
|
||
|
}
|
||
|
|
||
|
state_set = get_state_set(accessible);
|
||
|
g_print("(%s, %s, %s, %s)\n", app_name, name, role_name, state_set);
|
||
|
spd_sayf(spd_conn, SPD_TEXT, "%s, %s", name, role_name);
|
||
|
g_free(state_set);
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
on_event(AtspiEvent *event,
|
||
|
void *data)
|
||
|
{
|
||
|
AtspiAccessible *application = NULL;
|
||
|
gchar *app_name = NULL;
|
||
|
|
||
|
if(event->source == NULL)
|
||
|
return;
|
||
|
|
||
|
/* We only care about focus/selection gain */
|
||
|
if(!event->detail1)
|
||
|
return;
|
||
|
|
||
|
application = atspi_accessible_get_application(event->source, NULL);
|
||
|
if(application == NULL)
|
||
|
return;
|
||
|
|
||
|
app_name = atspi_accessible_get_name(application, NULL);
|
||
|
|
||
|
if((filter_name != NULL) && (g_strcmp0 (app_name, filter_name) != 0))
|
||
|
goto clean;
|
||
|
|
||
|
print_info(event->source, app_name);
|
||
|
|
||
|
clean:
|
||
|
g_free(app_name);
|
||
|
}
|
||
|
|
||
|
static gchar*
|
||
|
parse_args(int *argc,
|
||
|
char ***argv)
|
||
|
{
|
||
|
GError *error = NULL;
|
||
|
GOptionContext *context;
|
||
|
static gchar *name = NULL;
|
||
|
static GOptionEntry entries [] =
|
||
|
{
|
||
|
{"application", 'a', 0, G_OPTION_ARG_STRING, &name, "Application name", NULL},
|
||
|
{NULL,},
|
||
|
};
|
||
|
|
||
|
context = g_option_context_new("");
|
||
|
g_option_context_add_main_entries(context, entries, NULL);
|
||
|
if(!g_option_context_parse (context, argc, argv, &error))
|
||
|
{
|
||
|
g_print("%s\n", error->message);
|
||
|
g_print("Use --help for more information.\n");
|
||
|
exit(0);
|
||
|
}
|
||
|
|
||
|
return name;
|
||
|
}
|
||
|
|
||
|
int main(int argc, gchar **argv)
|
||
|
{
|
||
|
AtspiEventListener *listener;
|
||
|
char username[64];
|
||
|
|
||
|
filter_name = parse_args(&argc, &argv);
|
||
|
if(!filter_name) {
|
||
|
g_print("NOTE: Application name to filter not specified. Showing "
|
||
|
"focus/selection changes for any application.\n");
|
||
|
}
|
||
|
if(getlogin_r(username, 64)) {
|
||
|
g_print("USERNAME not found. Error.\n");
|
||
|
exit(1);
|
||
|
}
|
||
|
spd_conn = spd_open("speak_selection", "main", username, SPD_MODE_SINGLE);
|
||
|
if(!spd_conn){
|
||
|
g_print("Error establishing speech dispatcher connection. Fatal error.");
|
||
|
exit(1);
|
||
|
}
|
||
|
|
||
|
atspi_init();
|
||
|
|
||
|
listener = atspi_event_listener_new(on_event, NULL, NULL);
|
||
|
|
||
|
//atspi_event_listener_register(listener, "object:state-changed:focused", NULL);
|
||
|
atspi_event_listener_register(listener, "object:text-caret-moved", NULL);
|
||
|
|
||
|
atspi_event_main();
|
||
|
spd_close(spd_conn);
|
||
|
return 0;
|
||
|
}
|