4 * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
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 SPLAY_GENERATE(key_bindings
, key_binding
, entry
, key_bindings_cmp
);
29 struct key_bindings key_bindings
;
30 struct key_bindings dead_key_bindings
;
33 key_bindings_cmp(struct key_binding
*bd1
, struct key_binding
*bd2
)
37 key1
= bd1
->key
& ~KEYC_PREFIX
;
38 key2
= bd2
->key
& ~KEYC_PREFIX
;
42 if (bd1
->key
& KEYC_PREFIX
&& !(bd2
->key
& KEYC_PREFIX
))
44 if (bd2
->key
& KEYC_PREFIX
&& !(bd1
->key
& KEYC_PREFIX
))
50 key_bindings_lookup(int key
)
52 struct key_binding bd
;
55 return (SPLAY_FIND(key_bindings
, &key_bindings
, &bd
));
59 key_bindings_add(int key
, int can_repeat
, struct cmd_list
*cmdlist
)
61 struct key_binding
*bd
;
63 key_bindings_remove(key
);
65 bd
= xmalloc(sizeof *bd
);
67 SPLAY_INSERT(key_bindings
, &key_bindings
, bd
);
69 bd
->can_repeat
= can_repeat
;
70 bd
->cmdlist
= cmdlist
;
74 key_bindings_remove(int key
)
76 struct key_binding
*bd
;
78 if ((bd
= key_bindings_lookup(key
)) == NULL
)
80 SPLAY_REMOVE(key_bindings
, &key_bindings
, bd
);
81 SPLAY_INSERT(key_bindings
, &dead_key_bindings
, bd
);
85 key_bindings_clean(void)
87 struct key_binding
*bd
;
89 while (!SPLAY_EMPTY(&dead_key_bindings
)) {
90 bd
= SPLAY_ROOT(&dead_key_bindings
);
91 SPLAY_REMOVE(key_bindings
, &dead_key_bindings
, bd
);
92 cmd_list_free(bd
->cmdlist
);
98 key_bindings_init(void)
100 static const struct {
103 const struct cmd_entry
*entry
;
105 { ' ', 0, &cmd_next_layout_entry
},
106 { '!', 0, &cmd_break_pane_entry
},
107 { '"', 0, &cmd_split_window_entry
},
108 { '#', 0, &cmd_list_buffers_entry
},
109 { '$', 0, &cmd_command_prompt_entry
},
110 { '%', 0, &cmd_split_window_entry
},
111 { '&', 0, &cmd_confirm_before_entry
},
112 { '(', 0, &cmd_switch_client_entry
},
113 { ')', 0, &cmd_switch_client_entry
},
114 { ',', 0, &cmd_command_prompt_entry
},
115 { '-', 0, &cmd_delete_buffer_entry
},
116 { '.', 0, &cmd_command_prompt_entry
},
117 { '0', 0, &cmd_select_window_entry
},
118 { '1', 0, &cmd_select_window_entry
},
119 { '2', 0, &cmd_select_window_entry
},
120 { '3', 0, &cmd_select_window_entry
},
121 { '4', 0, &cmd_select_window_entry
},
122 { '5', 0, &cmd_select_window_entry
},
123 { '6', 0, &cmd_select_window_entry
},
124 { '7', 0, &cmd_select_window_entry
},
125 { '8', 0, &cmd_select_window_entry
},
126 { '9', 0, &cmd_select_window_entry
},
127 { ':', 0, &cmd_command_prompt_entry
},
128 { ';', 0, &cmd_last_pane_entry
},
129 { '=', 0, &cmd_choose_buffer_entry
},
130 { '?', 0, &cmd_list_keys_entry
},
131 { 'D', 0, &cmd_choose_client_entry
},
132 { 'L', 0, &cmd_switch_client_entry
},
133 { '[', 0, &cmd_copy_mode_entry
},
134 { '\'', 0, &cmd_command_prompt_entry
},
135 { '\002', /* C-b */ 0, &cmd_send_prefix_entry
},
136 { '\017', /* C-o */ 0, &cmd_rotate_window_entry
},
137 { '\032', /* C-z */ 0, &cmd_suspend_client_entry
},
138 { ']', 0, &cmd_paste_buffer_entry
},
139 { 'c', 0, &cmd_new_window_entry
},
140 { 'd', 0, &cmd_detach_client_entry
},
141 { 'f', 0, &cmd_command_prompt_entry
},
142 { 'i', 0, &cmd_display_message_entry
},
143 { 'l', 0, &cmd_last_window_entry
},
144 { 'n', 0, &cmd_next_window_entry
},
145 { 'o', 0, &cmd_select_pane_entry
},
146 { 'p', 0, &cmd_previous_window_entry
},
147 { 'q', 0, &cmd_display_panes_entry
},
148 { 'r', 0, &cmd_refresh_client_entry
},
149 { 's', 0, &cmd_choose_session_entry
},
150 { 't', 0, &cmd_clock_mode_entry
},
151 { 'w', 0, &cmd_choose_window_entry
},
152 { 'x', 0, &cmd_confirm_before_entry
},
153 { '{', 0, &cmd_swap_pane_entry
},
154 { '}', 0, &cmd_swap_pane_entry
},
155 { '~', 0, &cmd_show_messages_entry
},
156 { '1' | KEYC_ESCAPE
, 0, &cmd_select_layout_entry
},
157 { '2' | KEYC_ESCAPE
, 0, &cmd_select_layout_entry
},
158 { '3' | KEYC_ESCAPE
, 0, &cmd_select_layout_entry
},
159 { '4' | KEYC_ESCAPE
, 0, &cmd_select_layout_entry
},
160 { '5' | KEYC_ESCAPE
, 0, &cmd_select_layout_entry
},
161 { KEYC_PPAGE
, 0, &cmd_copy_mode_entry
},
162 { 'n' | KEYC_ESCAPE
, 0, &cmd_next_window_entry
},
163 { 'o' | KEYC_ESCAPE
, 0, &cmd_rotate_window_entry
},
164 { 'p' | KEYC_ESCAPE
, 0, &cmd_previous_window_entry
},
165 { KEYC_UP
, 1, &cmd_select_pane_entry
},
166 { KEYC_DOWN
, 1, &cmd_select_pane_entry
},
167 { KEYC_LEFT
, 1, &cmd_select_pane_entry
},
168 { KEYC_RIGHT
, 1, &cmd_select_pane_entry
},
169 { KEYC_UP
| KEYC_ESCAPE
, 1, &cmd_resize_pane_entry
},
170 { KEYC_DOWN
| KEYC_ESCAPE
, 1, &cmd_resize_pane_entry
},
171 { KEYC_LEFT
| KEYC_ESCAPE
, 1, &cmd_resize_pane_entry
},
172 { KEYC_RIGHT
| KEYC_ESCAPE
, 1, &cmd_resize_pane_entry
},
173 { KEYC_UP
| KEYC_CTRL
, 1, &cmd_resize_pane_entry
},
174 { KEYC_DOWN
| KEYC_CTRL
, 1, &cmd_resize_pane_entry
},
175 { KEYC_LEFT
| KEYC_CTRL
, 1, &cmd_resize_pane_entry
},
176 { KEYC_RIGHT
| KEYC_CTRL
, 1, &cmd_resize_pane_entry
},
180 struct cmd_list
*cmdlist
;
182 SPLAY_INIT(&key_bindings
);
184 for (i
= 0; i
< nitems(table
); i
++) {
185 cmdlist
= xmalloc(sizeof *cmdlist
);
186 TAILQ_INIT(&cmdlist
->list
);
187 cmdlist
->references
= 1;
189 cmd
= xmalloc(sizeof *cmd
);
190 cmd
->entry
= table
[i
].entry
;
191 if (cmd
->entry
->key_binding
!= NULL
)
192 cmd
->entry
->key_binding(cmd
, table
[i
].key
);
194 cmd
->args
= args_create(0);
195 TAILQ_INSERT_HEAD(&cmdlist
->list
, cmd
, qentry
);
198 table
[i
].key
| KEYC_PREFIX
, table
[i
].can_repeat
, cmdlist
);
203 key_bindings_error(struct cmd_ctx
*ctx
, const char *fmt
, ...)
209 xvasprintf(&msg
, fmt
, ap
);
212 *msg
= toupper((u_char
) *msg
);
213 status_message_set(ctx
->curclient
, "%s", msg
);
218 key_bindings_print(struct cmd_ctx
*ctx
, const char *fmt
, ...)
220 struct winlink
*wl
= ctx
->curclient
->session
->curw
;
223 if (wl
->window
->active
->mode
!= &window_copy_mode
) {
224 window_pane_reset_mode(wl
->window
->active
);
225 window_pane_set_mode(wl
->window
->active
, &window_copy_mode
);
226 window_copy_init_for_output(wl
->window
->active
);
230 window_copy_vadd(wl
->window
->active
, fmt
, ap
);
235 key_bindings_info(struct cmd_ctx
*ctx
, const char *fmt
, ...)
240 if (options_get_number(&global_options
, "quiet"))
244 xvasprintf(&msg
, fmt
, ap
);
247 *msg
= toupper((u_char
) *msg
);
248 status_message_set(ctx
->curclient
, "%s", msg
);
253 key_bindings_dispatch(struct key_binding
*bd
, struct client
*c
)
262 ctx
.error
= key_bindings_error
;
263 ctx
.print
= key_bindings_print
;
264 ctx
.info
= key_bindings_info
;
266 ctx
.cmdclient
= NULL
;
269 TAILQ_FOREACH(cmd
, &bd
->cmdlist
->list
, qentry
) {
270 if (!(cmd
->entry
->flags
& CMD_READONLY
))
273 if (!readonly
&& c
->flags
& CLIENT_READONLY
) {
274 key_bindings_info(&ctx
, "Client is read-only");
278 cmd_list_exec(bd
->cmdlist
, &ctx
);