int cmd_search(context_t *context) { Window *list; xdo_search_t search; unsigned int nwindows; unsigned int i; int c; int op_sync = False; int search_title = 0; int search_name = 0; int out_shell = 0; char out_prefix[17] = {'\0'}; int search_class = 0; int search_classname = 0; typedef enum { opt_unused, opt_title, opt_onlyvisible, opt_name, opt_shell, opt_prefix, opt_class, opt_maxdepth, opt_pid, opt_help, opt_any, opt_all, opt_screen, opt_classname, opt_desktop, opt_limit, opt_sync } optlist_t; struct option longopts[] = { { "all", no_argument, NULL, opt_all }, { "any", no_argument, NULL, opt_any }, { "class", no_argument, NULL, opt_class }, { "classname", no_argument, NULL, opt_classname }, { "help", no_argument, NULL, opt_help }, { "maxdepth", required_argument, NULL, opt_maxdepth }, { "name", no_argument, NULL, opt_name }, { "shell", no_argument, NULL, opt_shell }, { "prefix", required_argument, NULL, opt_prefix }, { "onlyvisible", 0, NULL, opt_onlyvisible }, { "pid", required_argument, NULL, opt_pid }, { "screen", required_argument, NULL, opt_screen }, { "title", no_argument, NULL, opt_title }, { "desktop", required_argument, NULL, opt_desktop }, { "limit", required_argument, NULL, opt_limit }, { "sync", no_argument, NULL, opt_sync }, { 0, 0, 0, 0 }, }; static const char *usage = "Usage: xdotool %s " "[options] regexp_pattern\n" "--class check regexp_pattern agains the window class\n" "--classname check regexp_pattern agains the window classname\n" "--maxdepth N set search depth to N. Default is infinite.\n" " -1 also means infinite.\n" "--onlyvisible matches only windows currently visible\n" "--pid PID only show windows belonging to specific process\n" " Not supported by all X11 applications\n" "--screen N only search a specific screen. Default is all screens\n" "--desktop N only search a specific desktop number\n" "--limit N break search after N results\n" "--name check regexp_pattern agains the window name\n" "--shell print results as shell array WINDOWS=( ... )\n" "--prefix STR use prefix (max 16 chars) for array name STRWINDOWS\n" "--title DEPRECATED. Same as --name.\n" "--all Require all conditions match a window. Default is --any\n" "--any Windows matching any condition will be reported\n" "--sync Wait until a search result is found.\n" "-h, --help show this help output\n" "\n" "If none of --name, --classname, or --class are specified, the \n" "defaults are: --name --classname --class\n"; memset(&search, 0, sizeof(xdo_search_t)); search.max_depth = -1; search.require = SEARCH_ANY; char *cmd = *context->argv; int option_index; while ((c = getopt_long_only(context->argc, context->argv, "+h", longopts, &option_index)) != -1) { switch (c) { case 0: break; case 'h': case opt_help: printf(usage, cmd); consume_args(context, context->argc); return EXIT_SUCCESS; case opt_maxdepth: search.max_depth = strtol(optarg, NULL, 0); break; case opt_pid: search.pid = atoi(optarg); search.searchmask |= SEARCH_PID; break; case opt_any: search.require = SEARCH_ANY; break; case opt_all: search.require = SEARCH_ALL; break; case opt_screen: search.screen = strtoul(optarg, NULL, 0); search.searchmask |= SEARCH_SCREEN; break; case opt_onlyvisible: search.only_visible = True; search.searchmask |= SEARCH_ONLYVISIBLE; break; case opt_class: search_class = True; break; case opt_classname: search_classname = True; break; case opt_title: fprintf(stderr, "This flag is deprecated. Assuming you mean --name (the" " window name).\n"); /* fall through */ case opt_name: search_name = True; break; case opt_shell: out_shell = True; break; case opt_prefix: strncpy(out_prefix, optarg, sizeof(out_prefix)-1); out_prefix[ sizeof(out_prefix)-1 ] = '\0'; //just in case break; case opt_desktop: search.desktop = strtol(optarg, NULL, 0); search.searchmask |= SEARCH_DESKTOP; break; case opt_limit: search.limit = atoi(optarg); break; case opt_sync: op_sync = True; break; default: fprintf(stderr, "Invalid usage\n"); fprintf(stderr, usage, cmd); return EXIT_FAILURE; } } consume_args(context, optind); /* We require a pattern or a pid to search for */ if (context->argc < 1 && search.pid == 0) { fprintf(stderr, usage, cmd); return EXIT_FAILURE; } if (context->argc > 0) { if (!search_title && !search_name && !search_class && !search_classname) { fprintf(stderr, "Defaulting to search window name, class, and classname\n"); search.searchmask |= (SEARCH_NAME | SEARCH_CLASS | SEARCH_CLASSNAME); search_name = 1; search_class = 1; search_classname = 1; } if (search_title) { search.searchmask |= SEARCH_NAME; search.winname = context->argv[0]; } if (search_name) { search.searchmask |= SEARCH_NAME; search.winname = context->argv[0]; } if (search_class) { search.searchmask |= SEARCH_CLASS; search.winclass = context->argv[0]; } if (search_classname) { search.searchmask |= SEARCH_CLASSNAME; search.winclassname = context->argv[0]; } consume_args(context, 1); } do { xdo_search_windows(context->xdo, &search, &list, &nwindows); if ( (context->argc == 0) || out_shell ) { /* only print if we're the last command or printing to shell*/ if (out_shell) printf("%s%s", out_prefix, "WINDOWS=("); for (i = 0; i < nwindows; i++) { window_print(list[i]); } if (out_shell) printf("%s",")\n"); } if (op_sync && nwindows == 0) { xdotool_debug(context, "No search results, still waiting..."); /* TODO(sissel): Make this tunable */ usleep(500000); } } while (op_sync && nwindows == 0); /* Free old list as it's malloc'd by xdo_search_windows */ if (context->windows != NULL) { free(context->windows); } context->windows = list; context->nwindows = nwindows; /* error if number of windows found is zero (behave like grep) but return success when being used inside eval (--shell option)*/ return (nwindows || out_shell ? EXIT_SUCCESS : EXIT_FAILURE); }
int cmd_exec(context_t *context) { char *cmd = *context->argv; char **command = NULL; int command_count = 0; int ret = EXIT_SUCCESS; int opsync = 0; int arity = -1; char *terminator = NULL; int c, i; typedef enum { opt_unused, opt_help, opt_sync, opt_args, opt_terminator } optlist_t; static struct option longopts[] = { { "help", no_argument, NULL, opt_help }, { "sync", no_argument, NULL, opt_sync }, { "args", required_argument, NULL, opt_args }, { "terminator", required_argument, NULL, opt_terminator }, { 0, 0, 0, 0 }, }; static const char *usage = "Usage: %s [options] command [arg1 arg2 ...] [terminator]\n" "--sync - only exit when the command given finishes. The default\n" " is to fork a child process and continue.\n" "--args N - how many arguments to expect in the exec command. This is\n" " useful for ending an exec and continuing with more xdotool\n" " commands\n" "--terminator TERM - similar to --args, specifies a terminator that\n" " marks the end of 'exec' arguments. This is useful\n" " for continuing with more xdotool commands.\n" "\n" "Unless --args OR --terminator is specified, the exec command is assumed\n" "to be the remainder of the command line.\n"; int option_index; while ((c = getopt_long_only(context->argc, context->argv, "+h", longopts, &option_index)) != -1) { switch (c) { case 'h': case opt_help: printf(usage, cmd); consume_args(context, context->argc); return EXIT_SUCCESS; break; case opt_sync: opsync = 1; break; case opt_args: arity = atoi(optarg); break; case opt_terminator: terminator = strdup(optarg); break; default: fprintf(stderr, usage, cmd); return EXIT_FAILURE; } } consume_args(context, optind); if (context->argc == 0) { fprintf(stderr, "No arguments given.\n"); fprintf(stderr, usage, cmd); return EXIT_FAILURE; } if (arity > 0 && terminator != NULL) { fprintf(stderr, "Don't use both --terminator and --args.\n"); return EXIT_FAILURE; } if (context->argc < arity) { fprintf(stderr, "You said '--args %d' but only gave %d arguments.\n", arity, context->argc); return EXIT_FAILURE; } command = calloc(context->argc + 1, sizeof(char *)); for (i=0; i < context->argc; i++) { if (arity > 0 && i == arity) { break; } /* if we have a terminator and the current argument matches it... */ if (terminator != NULL && strcmp(terminator, context->argv[i]) == 0) { command_count++; /* Consume the terminator, too */ break; } command[i] = strdup(context->argv[i]); command_count = i + 1; /* i starts at 0 */ xdotool_debug(context, "Exec arg[%d]: %s", i, command[i]); } command[i] = NULL; pid_t child; child = fork(); if (child == 0) { /* child */ execvp(command[0], command); /* if we get here, there was an error */ perror("execvp failed"); exit(errno); } else { /* parent */ if (opsync) { int status = 0; waitpid(child, &status, 0); ret = WEXITSTATUS(status); } } consume_args(context, command_count); if (terminator != NULL) { free(terminator); } for (i=0; i < command_count; i++) { free(command[i]); } free(command); return ret; }
int cmd_type(context_t *context) { int ret = 0; int i; int c; char *cmd = *context->argv; char *window_arg = NULL; int arity = -1; char *terminator = NULL; char *file = NULL; FILE *input = NULL; char *buffer = NULL; char *marker = NULL; size_t bytes_read = 0; char **data = NULL; /* stuff to type */ int data_count = 0; int args_count = 0; charcodemap_t *active_mods = NULL; int active_mods_n; /* Options */ int clear_modifiers = 0; useconds_t delay = 12000; /* 12ms between keystrokes default */ typedef enum { opt_unused, opt_clearmodifiers, opt_delay, opt_help, opt_window, opt_args, opt_terminator, opt_file } optlist_t; struct option longopts[] = { { "clearmodifiers", no_argument, NULL, opt_clearmodifiers }, { "delay", required_argument, NULL, opt_delay }, { "help", no_argument, NULL, opt_help }, { "window", required_argument, NULL, opt_window }, { "args", required_argument, NULL, opt_args }, { "terminator", required_argument, NULL, opt_terminator }, { "file", required_argument, NULL, opt_file }, { 0, 0, 0, 0 }, }; static const char *usage = "Usage: %s [--window windowid] [--delay milliseconds] " "<things to type>\n" "--window <windowid> - specify a window to send keys to\n" "--delay <milliseconds> - delay between keystrokes\n" "--clearmodifiers - reset active modifiers (alt, etc) while typing\n" "--args N - how many arguments to expect in the exec command. This is\n" " useful for ending an exec and continuing with more xdotool\n" " commands\n" "--terminator TERM - similar to --args, specifies a terminator that\n" " marks the end of 'exec' arguments. This is useful\n" " for continuing with more xdotool commands.\n" "--file <filepath> - specify a file, the contents of which will be\n" " be typed as if passed as an argument. The filepath\n" " may also be '-' to read from stdin.\n" "-h, --help - show this help output\n"; int option_index; while ((c = getopt_long_only(context->argc, context->argv, "+w:d:ch", longopts, &option_index)) != -1) { switch (c) { case opt_window: window_arg = strdup(optarg); break; case opt_delay: /* --delay is in milliseconds, convert to microseconds */ delay = strtoul(optarg, NULL, 0) * 1000; break; case opt_clearmodifiers: clear_modifiers = 1; break; case opt_help: printf(usage, cmd); consume_args(context, context->argc); return EXIT_SUCCESS; break; case opt_args: arity = atoi(optarg); break; case opt_terminator: terminator = strdup(optarg); break; case opt_file: file = strdup(optarg); break; default: fprintf(stderr, usage, cmd); return EXIT_FAILURE; } } consume_args(context, optind); if (context->argc == 0 && file == NULL) { fprintf(stderr, "You specified the wrong number of args.\n"); fprintf(stderr, usage, cmd); return 1; } if (arity > 0 && terminator != NULL) { fprintf(stderr, "Don't use both --terminator and --args.\n"); return EXIT_FAILURE; } if (context->argc < arity) { fprintf(stderr, "You said '--args %d' but only gave %d arguments.\n", arity, context->argc); return EXIT_FAILURE; } if (file != NULL) { data = calloc(1 + context->argc, sizeof(char *)); /* determine whether reading from a file or from stdin */ if (!strcmp(file, "-")) { input = fdopen(0, "r"); } else { input = fopen(file, "r"); if (input == NULL) { fprintf(stderr, "Failure opening '%s': %s\n", file, strerror(errno)); return EXIT_FAILURE; } } while (feof(input) == 0) { marker = realloc(buffer, bytes_read + 4096); if (marker == NULL) { fprintf(stderr, "Failure allocating for '%s': %s\n", file, strerror(errno)); return EXIT_FAILURE; } buffer = marker; marker = buffer + bytes_read; if (fgets(marker, 4096, input) != NULL) { bytes_read = (marker - buffer) + strlen(marker); } if (ferror(input) != 0) { fprintf(stderr, "Failure reading '%s': %s\n", file, strerror(errno)); return EXIT_FAILURE; } } data[0] = buffer; data_count++; fclose(input); } else { data = calloc(context->argc, sizeof(char *)); } /* Apply any --arity or --terminator */ for (i=0; i < context->argc; i++) { if (arity > 0 && i == arity) { data[data_count] = NULL; break; } /* if we have a terminator and the current argument matches it... */ if (terminator != NULL && strcmp(terminator, context->argv[i]) == 0) { data[data_count] = NULL; args_count++; /* Consume the terminator, too */ break; } data[data_count] = strdup(context->argv[i]); xdotool_debug(context, "Exec arg[%d]: %s", i, data[data_count]); data_count++; args_count++; } window_each(context, window_arg, { if (clear_modifiers) { xdo_get_active_modifiers(context->xdo, &active_mods, &active_mods_n); xdo_clear_active_modifiers(context->xdo, window, active_mods, active_mods_n); } for (i = 0; i < data_count; i++) { //printf("Typing: '%s'\n", context->argv[i]); int tmp = xdo_enter_text_window(context->xdo, window, data[i], delay); if (tmp) { fprintf(stderr, "xdo_enter_text_window reported an error\n"); } ret += tmp; } if (clear_modifiers) { xdo_set_active_modifiers(context->xdo, window, active_mods, active_mods_n); free(active_mods); } }); /* window_each(...) */