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
= xmalloc(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)
84 wme
= TAILQ_FIRST(&wp
->modes
);
85 if (wme
== NULL
|| wme
->mode
->key_table
== NULL
) {
86 if (window_pane_key(wp
, tc
, s
, wl
, key
, NULL
) != 0)
90 table
= key_bindings_get_table(wme
->mode
->key_table(wme
), 1);
92 bd
= key_bindings_get(table
, key
& ~KEYC_MASK_FLAGS
);
95 after
= key_bindings_dispatch(bd
, after
, tc
, NULL
, target
);
96 key_bindings_unref_table(table
);
101 static struct cmdq_item
*
102 cmd_send_keys_inject_string(struct cmdq_item
*item
, struct cmdq_item
*after
,
103 struct args
*args
, int i
)
105 const char *s
= args_string(args
, i
);
106 struct utf8_data
*ud
, *loop
;
113 if (args_has(args
, 'H')) {
114 n
= strtol(s
, &endptr
, 16);
115 if (*s
=='\0' || n
< 0 || n
> 0xff || *endptr
!= '\0')
117 return (cmd_send_keys_inject_key(item
, after
, args
,
121 literal
= args_has(args
, 'l');
123 key
= key_string_lookup_string(s
);
124 if (key
!= KEYC_NONE
&& key
!= KEYC_UNKNOWN
) {
125 after
= cmd_send_keys_inject_key(item
, after
, args
,
133 ud
= utf8_fromcstr(s
);
134 for (loop
= ud
; loop
->size
!= 0; loop
++) {
135 if (loop
->size
== 1 && loop
->data
[0] <= 0x7f)
138 if (utf8_from_data(loop
, &uc
) != UTF8_DONE
)
142 after
= cmd_send_keys_inject_key(item
, after
, args
,
150 static enum cmd_retval
151 cmd_send_keys_exec(struct cmd
*self
, struct cmdq_item
*item
)
153 struct args
*args
= cmd_get_args(self
);
154 struct cmd_find_state
*target
= cmdq_get_target(item
);
155 struct client
*tc
= cmdq_get_target_client(item
);
156 struct session
*s
= target
->s
;
157 struct winlink
*wl
= target
->wl
;
158 struct window_pane
*wp
= target
->wp
;
159 struct key_event
*event
= cmdq_get_event(item
);
160 struct mouse_event
*m
= &event
->m
;
161 struct window_mode_entry
*wme
= TAILQ_FIRST(&wp
->modes
);
162 struct cmdq_item
*after
= item
;
165 u_int count
= args_count(args
);
168 if (args_has(args
, 'N')) {
169 np
= args_strtonum_and_expand(args
, 'N', 1, UINT_MAX
, item
,
172 cmdq_error(item
, "repeat count %s", cause
);
174 return (CMD_RETURN_ERROR
);
176 if (wme
!= NULL
&& (args_has(args
, 'X') || count
== 0)) {
177 if (wme
->mode
->command
== NULL
) {
178 cmdq_error(item
, "not in a mode");
179 return (CMD_RETURN_ERROR
);
185 if (args_has(args
, 'X')) {
186 if (wme
== NULL
|| wme
->mode
->command
== NULL
) {
187 cmdq_error(item
, "not in a mode");
188 return (CMD_RETURN_ERROR
);
192 wme
->mode
->command(wme
, tc
, s
, wl
, args
, m
);
193 return (CMD_RETURN_NORMAL
);
196 if (args_has(args
, 'M')) {
197 wp
= cmd_mouse_pane(m
, &s
, NULL
);
199 cmdq_error(item
, "no mouse target");
200 return (CMD_RETURN_ERROR
);
202 window_pane_key(wp
, tc
, s
, wl
, m
->key
, m
);
203 return (CMD_RETURN_NORMAL
);
206 if (cmd_get_entry(self
) == &cmd_send_prefix_entry
) {
207 if (args_has(args
, '2'))
208 key
= options_get_number(s
->options
, "prefix2");
210 key
= options_get_number(s
->options
, "prefix");
211 cmd_send_keys_inject_key(item
, item
, args
, key
);
212 return (CMD_RETURN_NORMAL
);
215 if (args_has(args
, 'R')) {
216 colour_palette_clear(&wp
->palette
);
217 input_reset(wp
->ictx
, 1);
218 wp
->flags
|= (PANE_STYLECHANGED
|PANE_REDRAW
);
222 if (args_has(args
, 'N') || args_has(args
, 'R'))
223 return (CMD_RETURN_NORMAL
);
224 for (; np
!= 0; np
--)
225 cmd_send_keys_inject_key(item
, NULL
, args
, event
->key
);
226 return (CMD_RETURN_NORMAL
);
229 for (; np
!= 0; np
--) {
230 for (i
= 0; i
< count
; i
++) {
231 after
= cmd_send_keys_inject_string(item
, after
, args
,
236 return (CMD_RETURN_NORMAL
);