blob: d56428b1dba1581a6d25e3c9a59dc387d1c5a3eb [file] [log] [blame] [raw]
Nicholas Marriott35876ea2009-06-01 22:58:49 +00001/* $OpenBSD$ */
2
3/*
4 * Copyright (c) 2007 Nicholas Marriott <nicm@users.sourceforge.net>
5 *
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.
9 *
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.
17 */
18
19#include <sys/types.h>
20
21#include <ctype.h>
22#include <stdlib.h>
23#include <string.h>
24
25#include "tmux.h"
26
Nicholas Marriott8ed91242012-01-21 11:12:13 +000027RB_GENERATE(key_bindings, key_binding, entry, key_bindings_cmp);
nicmbded7432015-04-20 15:34:56 +000028RB_GENERATE(key_tables, key_table, entry, key_table_cmp);
29struct key_tables key_tables = RB_INITIALIZER(&key_tables);
Nicholas Marriott35876ea2009-06-01 22:58:49 +000030
nicmbded7432015-04-20 15:34:56 +000031int
32key_table_cmp(struct key_table *e1, struct key_table *e2)
33{
34 return (strcmp(e1->name, e2->name));
35}
Nicholas Marriott35876ea2009-06-01 22:58:49 +000036
37int
38key_bindings_cmp(struct key_binding *bd1, struct key_binding *bd2)
39{
nicmbded7432015-04-20 15:34:56 +000040 return (bd1->key - bd2->key);
Nicholas Marriott35876ea2009-06-01 22:58:49 +000041}
42
nicmbded7432015-04-20 15:34:56 +000043struct key_table *
44key_bindings_get_table(const char *name, int create)
Nicholas Marriott35876ea2009-06-01 22:58:49 +000045{
nicmbded7432015-04-20 15:34:56 +000046 struct key_table table_find, *table;
Nicholas Marriott35876ea2009-06-01 22:58:49 +000047
nicmbded7432015-04-20 15:34:56 +000048 table_find.name = name;
49 table = RB_FIND(key_tables, &key_tables, &table_find);
50 if (table != NULL || !create)
51 return (table);
52
53 table = xmalloc(sizeof *table);
54 table->name = xstrdup(name);
55 RB_INIT(&table->key_bindings);
56
57 table->references = 1; /* one reference in key_tables */
58 RB_INSERT(key_tables, &key_tables, table);
59
60 return (table);
Nicholas Marriott35876ea2009-06-01 22:58:49 +000061}
62
63void
nicmbded7432015-04-20 15:34:56 +000064key_bindings_unref_table(struct key_table *table)
Nicholas Marriott35876ea2009-06-01 22:58:49 +000065{
66 struct key_binding *bd;
67
nicmbded7432015-04-20 15:34:56 +000068 if (--table->references != 0)
69 return;
70
71 while (!RB_EMPTY(&table->key_bindings)) {
72 bd = RB_ROOT(&table->key_bindings);
73 RB_REMOVE(key_bindings, &table->key_bindings, bd);
74 cmd_list_free(bd->cmdlist);
75 free(bd);
76 }
77
78 free((void *)table->name);
79 free(table);
80}
81
82void
83key_bindings_add(const char *name, int key, int can_repeat,
84 struct cmd_list *cmdlist)
85{
86 struct key_table *table;
87 struct key_binding bd_find, *bd;
88
89 table = key_bindings_get_table(name, 1);
90
91 bd_find.key = key;
92 bd = RB_FIND(key_bindings, &table->key_bindings, &bd_find);
93 if (bd != NULL) {
94 RB_REMOVE(key_bindings, &table->key_bindings, bd);
95 cmd_list_free(bd->cmdlist);
96 free(bd);
97 }
Nicholas Marriott15a64b82009-12-03 22:50:09 +000098
Nicholas Marriott9e49ec62009-07-12 17:33:18 +000099 bd = xmalloc(sizeof *bd);
100 bd->key = key;
nicmbded7432015-04-20 15:34:56 +0000101 RB_INSERT(key_bindings, &table->key_bindings, bd);
Nicholas Marriott15a64b82009-12-03 22:50:09 +0000102
Nicholas Marriott35876ea2009-06-01 22:58:49 +0000103 bd->can_repeat = can_repeat;
104 bd->cmdlist = cmdlist;
105}
106
107void
nicmbded7432015-04-20 15:34:56 +0000108key_bindings_remove(const char *name, int key)
Nicholas Marriott35876ea2009-06-01 22:58:49 +0000109{
nicmbded7432015-04-20 15:34:56 +0000110 struct key_table *table;
111 struct key_binding bd_find, *bd;
Nicholas Marriott35876ea2009-06-01 22:58:49 +0000112
nicmbded7432015-04-20 15:34:56 +0000113 table = key_bindings_get_table(name, 0);
114 if (table == NULL)
Nicholas Marriott35876ea2009-06-01 22:58:49 +0000115 return;
nicmbded7432015-04-20 15:34:56 +0000116
117 bd_find.key = key;
118 bd = RB_FIND(key_bindings, &table->key_bindings, &bd_find);
119 if (bd == NULL)
120 return;
121
122 RB_REMOVE(key_bindings, &table->key_bindings, bd);
nicm53cbae52014-05-14 06:21:19 +0000123 cmd_list_free(bd->cmdlist);
124 free(bd);
nicmbded7432015-04-20 15:34:56 +0000125
126 if (RB_EMPTY(&table->key_bindings)) {
127 RB_REMOVE(key_tables, &key_tables, table);
128 key_bindings_unref_table(table);
129 }
130}
131
132void
133key_bindings_remove_table(const char *name)
134{
135 struct key_table *table;
136
137 table = key_bindings_get_table(name, 0);
138 if (table != NULL) {
139 RB_REMOVE(key_tables, &key_tables, table);
140 key_bindings_unref_table(table);
141 }
Nicholas Marriott35876ea2009-06-01 22:58:49 +0000142}
143
144void
145key_bindings_init(void)
146{
nicm1d1208e2015-04-25 18:49:01 +0000147 static const char *defaults[] = {
nicm45dfc5a2014-10-20 22:29:25 +0000148 "bind C-b send-prefix",
149 "bind C-o rotate-window",
150 "bind C-z suspend-client",
151 "bind Space next-layout",
152 "bind ! break-pane",
153 "bind '\"' split-window",
154 "bind '#' list-buffers",
155 "bind '$' command-prompt -I'#S' \"rename-session '%%'\"",
156 "bind % split-window -h",
157 "bind & confirm-before -p\"kill-window #W? (y/n)\" kill-window",
158 "bind \"'\" command-prompt -pindex \"select-window -t ':%%'\"",
159 "bind ( switch-client -p",
160 "bind ) switch-client -n",
161 "bind , command-prompt -I'#W' \"rename-window '%%'\"",
162 "bind - delete-buffer",
163 "bind . command-prompt \"move-window -t '%%'\"",
164 "bind 0 select-window -t:0",
165 "bind 1 select-window -t:1",
166 "bind 2 select-window -t:2",
167 "bind 3 select-window -t:3",
168 "bind 4 select-window -t:4",
169 "bind 5 select-window -t:5",
170 "bind 6 select-window -t:6",
171 "bind 7 select-window -t:7",
172 "bind 8 select-window -t:8",
173 "bind 9 select-window -t:9",
174 "bind : command-prompt",
175 "bind \\; last-pane",
176 "bind = choose-buffer",
177 "bind ? list-keys",
178 "bind D choose-client",
179 "bind L switch-client -l",
180 "bind [ copy-mode",
181 "bind ] paste-buffer",
182 "bind c new-window",
183 "bind d detach-client",
184 "bind f command-prompt \"find-window '%%'\"",
185 "bind i display-message",
186 "bind l last-window",
187 "bind n next-window",
188 "bind o select-pane -t:.+",
189 "bind p previous-window",
190 "bind q display-panes",
191 "bind r refresh-client",
192 "bind s choose-tree",
193 "bind t clock-mode",
194 "bind w choose-window",
195 "bind x confirm-before -p\"kill-pane #P? (y/n)\" kill-pane",
196 "bind z resize-pane -Z",
197 "bind { swap-pane -U",
198 "bind } swap-pane -D",
199 "bind '~' show-messages",
200 "bind PPage copy-mode -u",
201 "bind -r Up select-pane -U",
202 "bind -r Down select-pane -D",
203 "bind -r Left select-pane -L",
204 "bind -r Right select-pane -R",
205 "bind M-1 select-layout even-horizontal",
206 "bind M-2 select-layout even-vertical",
207 "bind M-3 select-layout main-horizontal",
208 "bind M-4 select-layout main-vertical",
209 "bind M-5 select-layout tiled",
210 "bind M-n next-window -a",
211 "bind M-o rotate-window -D",
212 "bind M-p previous-window -a",
213 "bind -r M-Up resize-pane -U 5",
214 "bind -r M-Down resize-pane -D 5",
215 "bind -r M-Left resize-pane -L 5",
216 "bind -r M-Right resize-pane -R 5",
217 "bind -r C-Up resize-pane -U",
218 "bind -r C-Down resize-pane -D",
219 "bind -r C-Left resize-pane -L",
220 "bind -r C-Right resize-pane -R",
nicmbf635e72015-04-19 21:34:21 +0000221 "bind -n MouseDown1Pane select-pane -t=\\; send-keys -M",
222 "bind -n MouseDrag1Border resize-pane -M",
223 "bind -n MouseDown1Status select-window -t=",
nicmd1337052015-04-21 15:34:32 +0000224 "bind -n MouseDrag1Pane if -Ft= '#{mouse_any_flag}' 'if -Ft= \"#{pane_in_mode}\" \"copy-mode -M\" \"send-keys -M\"' 'copy-mode -M'",
Nicholas Marriott35876ea2009-06-01 22:58:49 +0000225 };
226 u_int i;
Nicholas Marriott35876ea2009-06-01 22:58:49 +0000227 struct cmd_list *cmdlist;
nicm1d1208e2015-04-25 18:49:01 +0000228 char *cause;
nicm45dfc5a2014-10-20 22:29:25 +0000229 int error;
230 struct cmd_q *cmdq;
Nicholas Marriott35876ea2009-06-01 22:58:49 +0000231
nicmabfb9652014-10-22 23:18:53 +0000232 cmdq = cmdq_new(NULL);
nicm45dfc5a2014-10-20 22:29:25 +0000233 for (i = 0; i < nitems(defaults); i++) {
234 error = cmd_string_parse(defaults[i], &cmdlist,
235 "<default-keys>", i, &cause);
236 if (error != 0)
237 fatalx("bad default key");
nicmbf635e72015-04-19 21:34:21 +0000238 cmdq_run(cmdq, cmdlist, NULL);
239 cmd_list_free (cmdlist);
Nicholas Marriott35876ea2009-06-01 22:58:49 +0000240 }
nicmabfb9652014-10-22 23:18:53 +0000241 cmdq_free(cmdq);
Nicholas Marriott35876ea2009-06-01 22:58:49 +0000242}
243
Nicholas Marriott35876ea2009-06-01 22:58:49 +0000244void
nicmbf635e72015-04-19 21:34:21 +0000245key_bindings_dispatch(struct key_binding *bd, struct client *c,
246 struct mouse_event *m)
Nicholas Marriott35876ea2009-06-01 22:58:49 +0000247{
Nicholas Marriottbb53c202010-02-06 22:55:31 +0000248 struct cmd *cmd;
249 int readonly;
Nicholas Marriott35876ea2009-06-01 22:58:49 +0000250
Nicholas Marriottbb53c202010-02-06 22:55:31 +0000251 readonly = 1;
Nicholas Marriott42e24132010-06-26 18:20:53 +0000252 TAILQ_FOREACH(cmd, &bd->cmdlist->list, qentry) {
Nicholas Marriottbb53c202010-02-06 22:55:31 +0000253 if (!(cmd->entry->flags & CMD_READONLY))
254 readonly = 0;
255 }
Nicholas Marriott20636d92013-03-24 09:54:10 +0000256 if (!readonly && (c->flags & CLIENT_READONLY)) {
nicm27404902014-04-17 07:55:43 +0000257 cmdq_error(c->cmdq, "client is read-only");
Nicholas Marriottbb53c202010-02-06 22:55:31 +0000258 return;
259 }
260
nicmbf635e72015-04-19 21:34:21 +0000261 cmdq_run(c->cmdq, bd->cmdlist, m);
Nicholas Marriott35876ea2009-06-01 22:58:49 +0000262}