4 * Copyright (c) 2008 Nicholas Marriott <nicholas.marriott@gmail.com>
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
15 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
16 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19 #include <sys/types.h>
27 * Send keys to client.
30 static enum cmd_retval
cmd_send_keys_exec(struct cmd
*, struct cmdq_item
*);
32 const struct cmd_entry cmd_send_keys_entry
= {
36 .args
= { "c:FHKlMN:Rt:X", 0, -1, NULL
},
37 .usage
= "[-FHKlMRX] [-c target-client] [-N repeat-count] "
38 CMD_TARGET_PANE_USAGE
" key ...",
40 .target
= { 't', CMD_FIND_PANE
, 0 },
42 .flags
= CMD_AFTERHOOK
|CMD_CLIENT_CFLAG
|CMD_CLIENT_CANFAIL
,
43 .exec
= cmd_send_keys_exec
46 const struct cmd_entry cmd_send_prefix_entry
= {
47 .name
= "send-prefix",
50 .args
= { "2t:", 0, 0, NULL
},
51 .usage
= "[-2] " CMD_TARGET_PANE_USAGE
,
53 .target
= { 't', CMD_FIND_PANE
, 0 },
55 .flags
= CMD_AFTERHOOK
,
56 .exec
= cmd_send_keys_exec
59 static struct cmdq_item
*
60 cmd_send_keys_inject_key(struct cmdq_item
*item
, struct cmdq_item
*after
,
61 struct args
*args
, key_code key
)
63 struct cmd_find_state
*target
= cmdq_get_target(item
);
64 struct client
*tc
= cmdq_get_target_client(item
);
65 struct session
*s
= target
->s
;
66 struct winlink
*wl
= target
->wl
;
67 struct window_pane
*wp
= target
->wp
;
68 struct window_mode_entry
*wme
;
69 struct key_table
*table
= NULL
;
70 struct key_binding
*bd
;
71 struct key_event
*event
;
73 if (args_has(args
, 'K')) {
76 event
= xcalloc(1, sizeof *event
);
77 event
->key
= key
|KEYC_SENT
;
78 memset(&event
->m
, 0, sizeof event
->m
);
79 if (server_client_handle_key(tc
, event
) == 0) {
86 wme
= TAILQ_FIRST(&wp
->modes
);
87 if (wme
== NULL
|| wme
->mode
->key_table
== NULL
) {
88 if (window_pane_key(wp
, tc
, s
, wl
, key
, NULL
) != 0)
92 table
= key_bindings_get_table(wme
->mode
->key_table(wme
), 1);
94 bd
= key_bindings_get(table
, key
& ~KEYC_MASK_FLAGS
);
97 after
= key_bindings_dispatch(bd
, after
, tc
, NULL
, target
);
98 key_bindings_unref_table(table
);
103 static struct cmdq_item
*
104 cmd_send_keys_inject_string(struct cmdq_item
*item
, struct cmdq_item
*after
,
105 struct args
*args
, int i
)
107 const char *s
= args_string(args
, i
);
108 struct utf8_data
*ud
, *loop
;
115 if (args_has(args
, 'H')) {
116 n
= strtol(s
, &endptr
, 16);
117 if (*s
=='\0' || n
< 0 || n
> 0xff || *endptr
!= '\0')
119 return (cmd_send_keys_inject_key(item
, after
, args
,
123 literal
= args_has(args
, 'l');
125 key
= key_string_lookup_string(s
);
126 if (key
!= KEYC_NONE
&& key
!= KEYC_UNKNOWN
) {
127 after
= cmd_send_keys_inject_key(item
, after
, args
,
135 ud
= utf8_fromcstr(s
);
136 for (loop
= ud
; loop
->size
!= 0; loop
++) {
137 if (loop
->size
== 1 && loop
->data
[0] <= 0x7f)
140 if (utf8_from_data(loop
, &uc
) != UTF8_DONE
)
144 after
= cmd_send_keys_inject_key(item
, after
, args
,
152 static enum cmd_retval
153 cmd_send_keys_exec(struct cmd
*self
, struct cmdq_item
*item
)
155 struct args
*args
= cmd_get_args(self
);
156 struct cmd_find_state
*target
= cmdq_get_target(item
);
157 struct client
*tc
= cmdq_get_target_client(item
);
158 struct session
*s
= target
->s
;
159 struct winlink
*wl
= target
->wl
;
160 struct window_pane
*wp
= target
->wp
;
161 struct key_event
*event
= cmdq_get_event(item
);
162 struct mouse_event
*m
= &event
->m
;
163 struct window_mode_entry
*wme
= TAILQ_FIRST(&wp
->modes
);
164 struct cmdq_item
*after
= item
;
167 u_int count
= args_count(args
);
170 if (args_has(args
, 'N')) {
171 np
= args_strtonum_and_expand(args
, 'N', 1, UINT_MAX
, item
,
174 cmdq_error(item
, "repeat count %s", cause
);
176 return (CMD_RETURN_ERROR
);
178 if (wme
!= NULL
&& (args_has(args
, 'X') || count
== 0)) {
179 if (wme
->mode
->command
== NULL
) {
180 cmdq_error(item
, "not in a mode");
181 return (CMD_RETURN_ERROR
);
187 if (args_has(args
, 'X')) {
188 if (wme
== NULL
|| wme
->mode
->command
== NULL
) {
189 cmdq_error(item
, "not in a mode");
190 return (CMD_RETURN_ERROR
);
194 wme
->mode
->command(wme
, tc
, s
, wl
, args
, m
);
195 return (CMD_RETURN_NORMAL
);
198 if (args_has(args
, 'M')) {
199 wp
= cmd_mouse_pane(m
, &s
, NULL
);
201 cmdq_error(item
, "no mouse target");
202 return (CMD_RETURN_ERROR
);
204 window_pane_key(wp
, tc
, s
, wl
, m
->key
, m
);
205 return (CMD_RETURN_NORMAL
);
208 if (cmd_get_entry(self
) == &cmd_send_prefix_entry
) {
209 if (args_has(args
, '2'))
210 key
= options_get_number(s
->options
, "prefix2");
212 key
= options_get_number(s
->options
, "prefix");
213 cmd_send_keys_inject_key(item
, item
, args
, key
);
214 return (CMD_RETURN_NORMAL
);
217 if (args_has(args
, 'R')) {
218 colour_palette_clear(&wp
->palette
);
219 input_reset(wp
->ictx
, 1);
220 wp
->flags
|= (PANE_STYLECHANGED
|PANE_REDRAW
);
224 if (args_has(args
, 'N') || args_has(args
, 'R'))
225 return (CMD_RETURN_NORMAL
);
226 for (; np
!= 0; np
--)
227 cmd_send_keys_inject_key(item
, NULL
, args
, event
->key
);
228 return (CMD_RETURN_NORMAL
);
231 for (; np
!= 0; np
--) {
232 for (i
= 0; i
< count
; i
++) {
233 after
= cmd_send_keys_inject_string(item
, after
, args
,
238 return (CMD_RETURN_NORMAL
);