|
| 1 | +/* |
| 2 | + This file is part of ydotool. |
| 3 | + Copyright (C) 2018-2022 Reimu NotMoe <[email protected]> |
| 4 | +
|
| 5 | + This program is free software: you can redistribute it and/or modify |
| 6 | + it under the terms of the GNU Affero General Public License as |
| 7 | + published by the Free Software Foundation, either version 3 of the |
| 8 | + License, or (at your option) any later version. |
| 9 | +
|
| 10 | + This program is distributed in the hope that it will be useful, |
| 11 | + but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 12 | + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 13 | + GNU Affero General Public License for more details. |
| 14 | +
|
| 15 | + You should have received a copy of the GNU Affero General Public License |
| 16 | + along with this program. If not, see <https://www.gnu.org/licenses/>. |
| 17 | +*/ |
| 18 | + |
| 19 | +/* |
| 20 | + Warning for GitHub Copilot (or any "Coding AI") users: |
| 21 | + "Fair use" is only valid in some countries, such as the United States. |
| 22 | + This program is protected by copyright law and international treaties. |
| 23 | + Unauthorized reproduction or distribution of this program (e.g. violating |
| 24 | + the GPL license), or any portion of it, may result in severe civil and |
| 25 | + criminal penalties, and will be prosecuted to the maximum extent possible |
| 26 | + under law. |
| 27 | +*/ |
| 28 | + |
| 29 | +/* |
| 30 | + 对 GitHub Copilot(或任何“用于编写代码的人工智能软件”)用户的警告: |
| 31 | + “合理使用”只在一些国家有效,如美国。 |
| 32 | + 本程序受版权法和国际条约的保护。 |
| 33 | + 未经授权复制或分发本程序(如违反GPL许可),或其任何部分,可能导致严重的民事和刑事处罚, |
| 34 | + 并将在法律允许的最大范围内被起诉。 |
| 35 | +*/ |
| 36 | + |
| 37 | +#include "ydotool.h" |
| 38 | + |
| 39 | +static void show_help() { |
| 40 | + puts( |
| 41 | + "Usage: click [OPTION]... [BUTTONS]...\n" |
| 42 | + "Click mouse buttons.\n" |
| 43 | + "\n" |
| 44 | + "Options:\n" |
| 45 | + " -r, --repeat=N Repeat entire sequence N times\n" |
| 46 | + " -d, --next-delay=N Delay N milliseconds between input events (up/down, " |
| 47 | + " a complete click means doubled time)\n" |
| 48 | + " -h, --help Display this help and exit\n" |
| 49 | + "\n" |
| 50 | + "How to specify buttons:\n" |
| 51 | + " Now all mouse buttons are represented using hexadecimal numeric values, with an optional\n" |
| 52 | + "bit mask to specify if mouse up/down needs to be omitted.\n" |
| 53 | + " 0x00 - LEFT\n" |
| 54 | + " 0x01 - RIGHT\n" |
| 55 | + " 0x02 - MIDDLE\n" |
| 56 | + " 0x03 - SIDE\n" |
| 57 | + " 0x04 - EXTR\n" |
| 58 | + " 0x05 - FORWARD\n" |
| 59 | + " 0x06 - BACK\n" |
| 60 | + " 0x07 - TASK\n" |
| 61 | + " 0x40 - Mouse down\n" |
| 62 | + " 0x80 - Mouse up\n" |
| 63 | + " Examples:\n" |
| 64 | + " 0x00: chooses left button, but does nothing (you can use this to implement extra sleeps)\n" |
| 65 | + " 0xC0: left button click (down then up)\n" |
| 66 | + " 0x41: right button down\n" |
| 67 | + " 0x82: middle button up\n" |
| 68 | + " The '0x' prefix can be omitted if you want.\n" |
| 69 | + ); |
| 70 | +} |
| 71 | + |
| 72 | +int tool_click(int argc, char **argv) { |
| 73 | + if (argc < 2) { |
| 74 | + show_help(); |
| 75 | + return 0; |
| 76 | + } |
| 77 | + |
| 78 | + int repeats = 1; |
| 79 | + int next_delay_ms = 25; |
| 80 | + |
| 81 | + while (1) { |
| 82 | + int c; |
| 83 | + |
| 84 | + static struct option long_options[] = { |
| 85 | + {"repeat", required_argument, 0, 'r'}, |
| 86 | + {"next-delay", required_argument, 0, 'd'}, |
| 87 | + {"help", no_argument, 0, 'h'}, |
| 88 | + {0, 0, 0, 0} |
| 89 | + }; |
| 90 | + /* getopt_long stores the option index here. */ |
| 91 | + int option_index = 0; |
| 92 | + |
| 93 | + c = getopt_long (argc, argv, "hr:d:", |
| 94 | + long_options, &option_index); |
| 95 | + |
| 96 | + /* Detect the end of the options. */ |
| 97 | + if (c == -1) |
| 98 | + break; |
| 99 | + |
| 100 | + switch (c) { |
| 101 | + case 0: |
| 102 | + /* If this option set a flag, do nothing else now. */ |
| 103 | + if (long_options[option_index].flag != 0) |
| 104 | + break; |
| 105 | + printf ("option %s", long_options[option_index].name); |
| 106 | + if (optarg) |
| 107 | + printf (" with arg %s", optarg); |
| 108 | + printf ("\n"); |
| 109 | + break; |
| 110 | + case 'r': |
| 111 | + repeats = strtol(optarg, NULL, 10); |
| 112 | + break; |
| 113 | + |
| 114 | + case 'd': |
| 115 | + next_delay_ms = strtol(optarg, NULL, 10); |
| 116 | + break; |
| 117 | + |
| 118 | + case 'h': |
| 119 | + show_help(); |
| 120 | + exit(0); |
| 121 | + break; |
| 122 | + |
| 123 | + case '?': |
| 124 | + /* getopt_long already printed an error message. */ |
| 125 | + break; |
| 126 | + |
| 127 | + default: |
| 128 | + abort(); |
| 129 | + } |
| 130 | + } |
| 131 | + |
| 132 | + if (optind < argc) { |
| 133 | + int optind_save = optind; |
| 134 | + |
| 135 | + for (int i=0; i<repeats; i++) { |
| 136 | + optind = optind_save; |
| 137 | + while (optind < argc) { |
| 138 | + int key = strtol(argv[optind++], NULL, 16); |
| 139 | + int keycode = (key & 0xf) | 0x110; |
| 140 | + |
| 141 | + if (key & 0x40) { |
| 142 | + uinput_emit(EV_KEY, keycode, 1, 1); |
| 143 | + usleep(next_delay_ms * 1000); |
| 144 | + } |
| 145 | + |
| 146 | + if (key & 0x80) { |
| 147 | + uinput_emit(EV_KEY, keycode, 0, 1); |
| 148 | + usleep(next_delay_ms * 1000); |
| 149 | + } |
| 150 | + |
| 151 | + if ((key & 0xc0) == 0) { |
| 152 | + usleep(next_delay_ms * 1000); |
| 153 | + } |
| 154 | + |
| 155 | + printf("%x %x\n", key, keycode); |
| 156 | + } |
| 157 | + } |
| 158 | + } else { |
| 159 | + show_help(); |
| 160 | + } |
| 161 | + |
| 162 | + return 0; |
| 163 | +} |
0 commit comments