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_split_window_entry
},
110 { '&', 0, &cmd_confirm_before_entry
},
111 { ',', 0, &cmd_command_prompt_entry
},
112 { '-', 0, &cmd_delete_buffer_entry
},
113 { '.', 0, &cmd_command_prompt_entry
},
114 { '0', 0, &cmd_select_window_entry
},
115 { '1', 0, &cmd_select_window_entry
},
116 { '2', 0, &cmd_select_window_entry
},
117 { '3', 0, &cmd_select_window_entry
},
118 { '4', 0, &cmd_select_window_entry
},
119 { '5', 0, &cmd_select_window_entry
},
120 { '6', 0, &cmd_select_window_entry
},
121 { '7', 0, &cmd_select_window_entry
},
122 { '8', 0, &cmd_select_window_entry
},
123 { '9', 0, &cmd_select_window_entry
},
124 { ':', 0, &cmd_command_prompt_entry
},
125 { '=', 0, &cmd_choose_buffer_entry
},
126 { '?', 0, &cmd_list_keys_entry
},
127 { 'D', 0, &cmd_choose_client_entry
},
128 { '[', 0, &cmd_copy_mode_entry
},
129 { '\'', 0, &cmd_command_prompt_entry
},
130 { '\002', /* C-b */ 0, &cmd_send_prefix_entry
},
131 { '\017', /* C-o */ 0, &cmd_rotate_window_entry
},
132 { '\032', /* C-z */ 0, &cmd_suspend_client_entry
},
133 { ']', 0, &cmd_paste_buffer_entry
},
134 { 'c', 0, &cmd_new_window_entry
},
135 { 'd', 0, &cmd_detach_client_entry
},
136 { 'f', 0, &cmd_command_prompt_entry
},
137 { 'i', 0, &cmd_display_message_entry
},
138 { 'l', 0, &cmd_last_window_entry
},
139 { 'n', 0, &cmd_next_window_entry
},
140 { 'o', 0, &cmd_select_pane_entry
},
141 { 'p', 0, &cmd_previous_window_entry
},
142 { 'q', 0, &cmd_display_panes_entry
},
143 { 'r', 0, &cmd_refresh_client_entry
},
144 { 's', 0, &cmd_choose_session_entry
},
145 { 't', 0, &cmd_clock_mode_entry
},
146 { 'w', 0, &cmd_choose_window_entry
},
147 { 'x', 0, &cmd_confirm_before_entry
},
148 { '{', 0, &cmd_swap_pane_entry
},
149 { '}', 0, &cmd_swap_pane_entry
},
150 { '~', 0, &cmd_show_messages_entry
},
151 { '1' | KEYC_ESCAPE
, 0, &cmd_select_layout_entry
},
152 { '2' | KEYC_ESCAPE
, 0, &cmd_select_layout_entry
},
153 { '3' | KEYC_ESCAPE
, 0, &cmd_select_layout_entry
},
154 { '4' | KEYC_ESCAPE
, 0, &cmd_select_layout_entry
},
155 { '5' | KEYC_ESCAPE
, 0, &cmd_select_layout_entry
},
156 { KEYC_PPAGE
, 0, &cmd_copy_mode_entry
},
157 { 'n' | KEYC_ESCAPE
, 0, &cmd_next_window_entry
},
158 { 'o' | KEYC_ESCAPE
, 0, &cmd_rotate_window_entry
},
159 { 'p' | KEYC_ESCAPE
, 0, &cmd_previous_window_entry
},
160 { KEYC_UP
, 1, &cmd_select_pane_entry
},
161 { KEYC_DOWN
, 1, &cmd_select_pane_entry
},
162 { KEYC_LEFT
, 1, &cmd_select_pane_entry
},
163 { KEYC_RIGHT
, 1, &cmd_select_pane_entry
},
164 { KEYC_UP
| KEYC_ESCAPE
, 1, &cmd_resize_pane_entry
},
165 { KEYC_DOWN
| KEYC_ESCAPE
, 1, &cmd_resize_pane_entry
},
166 { KEYC_LEFT
| KEYC_ESCAPE
, 1, &cmd_resize_pane_entry
},
167 { KEYC_RIGHT
| KEYC_ESCAPE
, 1, &cmd_resize_pane_entry
},
168 { KEYC_UP
| KEYC_CTRL
, 1, &cmd_resize_pane_entry
},
169 { KEYC_DOWN
| KEYC_CTRL
, 1, &cmd_resize_pane_entry
},
170 { KEYC_LEFT
| KEYC_CTRL
, 1, &cmd_resize_pane_entry
},
171 { KEYC_RIGHT
| KEYC_CTRL
, 1, &cmd_resize_pane_entry
},
175 struct cmd_list
*cmdlist
;
177 SPLAY_INIT(&key_bindings
);
179 for (i
= 0; i
< nitems(table
); i
++) {
180 cmdlist
= xmalloc(sizeof *cmdlist
);
181 TAILQ_INIT(&cmdlist
->list
);
182 cmdlist
->references
= 1;
184 cmd
= xmalloc(sizeof *cmd
);
185 cmd
->entry
= table
[i
].entry
;
187 if (cmd
->entry
->init
!= NULL
)
188 cmd
->entry
->init(cmd
, table
[i
].key
);
189 TAILQ_INSERT_HEAD(&cmdlist
->list
, cmd
, qentry
);
192 table
[i
].key
| KEYC_PREFIX
, table
[i
].can_repeat
, cmdlist
);
197 key_bindings_error(struct cmd_ctx
*ctx
, const char *fmt
, ...)
203 xvasprintf(&msg
, fmt
, ap
);
206 *msg
= toupper((u_char
) *msg
);
207 status_message_set(ctx
->curclient
, "%s", msg
);
212 key_bindings_print(struct cmd_ctx
*ctx
, const char *fmt
, ...)
214 struct winlink
*wl
= ctx
->curclient
->session
->curw
;
217 if (wl
->window
->active
->mode
!= &window_copy_mode
) {
218 window_pane_reset_mode(wl
->window
->active
);
219 window_pane_set_mode(wl
->window
->active
, &window_copy_mode
);
220 window_copy_init_for_output(wl
->window
->active
);
224 window_copy_vadd(wl
->window
->active
, fmt
, ap
);
229 key_bindings_info(struct cmd_ctx
*ctx
, const char *fmt
, ...)
234 if (options_get_number(&global_options
, "quiet"))
238 xvasprintf(&msg
, fmt
, ap
);
241 *msg
= toupper((u_char
) *msg
);
242 status_message_set(ctx
->curclient
, "%s", msg
);
247 key_bindings_dispatch(struct key_binding
*bd
, struct client
*c
)
256 ctx
.error
= key_bindings_error
;
257 ctx
.print
= key_bindings_print
;
258 ctx
.info
= key_bindings_info
;
260 ctx
.cmdclient
= NULL
;
263 TAILQ_FOREACH(cmd
, &bd
->cmdlist
->list
, qentry
) {
264 if (!(cmd
->entry
->flags
& CMD_READONLY
))
267 if (!readonly
&& c
->flags
& CLIENT_READONLY
) {
268 key_bindings_info(&ctx
, "Client is read-only");
272 cmd_list_exec(bd
->cmdlist
, &ctx
);