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>
28 * This file is rather misleadingly named, it contains the code which takes a
29 * key code and translates it into something suitable to be sent to the
30 * application running in a pane (similar to input.c does in the other
31 * direction with output).
34 struct input_key_ent
{
39 #define INPUTKEY_KEYPAD 0x1 /* keypad key */
40 #define INPUTKEY_CURSOR 0x2 /* cursor key */
43 const struct input_key_ent input_keys
[] = {
45 { KEYC_BSPACE
, "\177", 0 },
48 { KEYC_F1
, "\033OP", 0 },
49 { KEYC_F2
, "\033OQ", 0 },
50 { KEYC_F3
, "\033OR", 0 },
51 { KEYC_F4
, "\033OS", 0 },
52 { KEYC_F5
, "\033[15~", 0 },
53 { KEYC_F6
, "\033[17~", 0 },
54 { KEYC_F7
, "\033[18~", 0 },
55 { KEYC_F8
, "\033[19~", 0 },
56 { KEYC_F9
, "\033[20~", 0 },
57 { KEYC_F10
, "\033[21~", 0 },
58 { KEYC_F11
, "\033[23~", 0 },
59 { KEYC_F12
, "\033[24~", 0 },
60 { KEYC_F13
, "\033[25~", 0 },
61 { KEYC_F14
, "\033[26~", 0 },
62 { KEYC_F15
, "\033[28~", 0 },
63 { KEYC_F16
, "\033[29~", 0 },
64 { KEYC_F17
, "\033[31~", 0 },
65 { KEYC_F18
, "\033[32~", 0 },
66 { KEYC_F19
, "\033[33~", 0 },
67 { KEYC_F20
, "\033[34~", 0 },
68 { KEYC_IC
, "\033[2~", 0 },
69 { KEYC_DC
, "\033[3~", 0 },
70 { KEYC_HOME
, "\033[1~", 0 },
71 { KEYC_END
, "\033[4~", 0 },
72 { KEYC_NPAGE
, "\033[6~", 0 },
73 { KEYC_PPAGE
, "\033[5~", 0 },
74 { KEYC_BTAB
, "\033[Z", 0 },
77 * Arrow keys. Cursor versions must come first. The codes are toggled
78 * between CSI and SS3 versions when ctrl is pressed.
80 { KEYC_UP
|KEYC_CTRL
, "\033[A", INPUTKEY_CURSOR
},
81 { KEYC_DOWN
|KEYC_CTRL
, "\033[B", INPUTKEY_CURSOR
},
82 { KEYC_RIGHT
|KEYC_CTRL
, "\033[C", INPUTKEY_CURSOR
},
83 { KEYC_LEFT
|KEYC_CTRL
, "\033[D", INPUTKEY_CURSOR
},
85 { KEYC_UP
, "\033OA", INPUTKEY_CURSOR
},
86 { KEYC_DOWN
, "\033OB", INPUTKEY_CURSOR
},
87 { KEYC_RIGHT
, "\033OC", INPUTKEY_CURSOR
},
88 { KEYC_LEFT
, "\033OD", INPUTKEY_CURSOR
},
90 { KEYC_UP
|KEYC_CTRL
, "\033OA", 0 },
91 { KEYC_DOWN
|KEYC_CTRL
, "\033OB", 0 },
92 { KEYC_RIGHT
|KEYC_CTRL
, "\033OC", 0 },
93 { KEYC_LEFT
|KEYC_CTRL
, "\033OD", 0 },
95 { KEYC_UP
, "\033[A", 0 },
96 { KEYC_DOWN
, "\033[B", 0 },
97 { KEYC_RIGHT
, "\033[C", 0 },
98 { KEYC_LEFT
, "\033[D", 0 },
100 /* Keypad keys. Keypad versions must come first. */
101 { KEYC_KP_SLASH
, "\033Oo", INPUTKEY_KEYPAD
},
102 { KEYC_KP_STAR
, "\033Oj", INPUTKEY_KEYPAD
},
103 { KEYC_KP_MINUS
, "\033Om", INPUTKEY_KEYPAD
},
104 { KEYC_KP_SEVEN
, "\033Ow", INPUTKEY_KEYPAD
},
105 { KEYC_KP_EIGHT
, "\033Ox", INPUTKEY_KEYPAD
},
106 { KEYC_KP_NINE
, "\033Oy", INPUTKEY_KEYPAD
},
107 { KEYC_KP_PLUS
, "\033Ok", INPUTKEY_KEYPAD
},
108 { KEYC_KP_FOUR
, "\033Ot", INPUTKEY_KEYPAD
},
109 { KEYC_KP_FIVE
, "\033Ou", INPUTKEY_KEYPAD
},
110 { KEYC_KP_SIX
, "\033Ov", INPUTKEY_KEYPAD
},
111 { KEYC_KP_ONE
, "\033Oq", INPUTKEY_KEYPAD
},
112 { KEYC_KP_TWO
, "\033Or", INPUTKEY_KEYPAD
},
113 { KEYC_KP_THREE
, "\033Os", INPUTKEY_KEYPAD
},
114 { KEYC_KP_ENTER
, "\033OM", INPUTKEY_KEYPAD
},
115 { KEYC_KP_ZERO
, "\033Op", INPUTKEY_KEYPAD
},
116 { KEYC_KP_PERIOD
, "\033On", INPUTKEY_KEYPAD
},
118 { KEYC_KP_SLASH
, "/", 0 },
119 { KEYC_KP_STAR
, "*", 0 },
120 { KEYC_KP_MINUS
, "-", 0 },
121 { KEYC_KP_SEVEN
, "7", 0 },
122 { KEYC_KP_EIGHT
, "8", 0 },
123 { KEYC_KP_NINE
, "9", 0 },
124 { KEYC_KP_PLUS
, "+", 0 },
125 { KEYC_KP_FOUR
, "4", 0 },
126 { KEYC_KP_FIVE
, "5", 0 },
127 { KEYC_KP_SIX
, "6", 0 },
128 { KEYC_KP_ONE
, "1", 0 },
129 { KEYC_KP_TWO
, "2", 0 },
130 { KEYC_KP_THREE
, "3", 0 },
131 { KEYC_KP_ENTER
, "\n", 0 },
132 { KEYC_KP_ZERO
, "0", 0 },
133 { KEYC_KP_PERIOD
, ".", 0 },
136 /* Translate a key code into an output key sequence. */
138 input_key(struct window_pane
*wp
, int key
)
140 const struct input_key_ent
*ike
;
146 log_debug2("writing key 0x%x", key
);
149 * If this is a normal 7-bit key, just send it, with a leading escape
152 if (key
!= KEYC_NONE
&& (key
& ~KEYC_ESCAPE
) < 0x100) {
153 if (key
& KEYC_ESCAPE
)
154 bufferevent_write(wp
->event
, "\033", 1);
155 ch
= key
& ~KEYC_ESCAPE
;
156 bufferevent_write(wp
->event
, &ch
, 1);
161 * Then try to look this up as an xterm key, if the flag to output them
164 if (options_get_number(&wp
->window
->options
, "xterm-keys")) {
165 if ((out
= xterm_keys_lookup(key
)) != NULL
) {
166 bufferevent_write(wp
->event
, out
, strlen(out
));
172 /* Otherwise look the key up in the table. */
173 for (i
= 0; i
< nitems(input_keys
); i
++) {
174 ike
= &input_keys
[i
];
176 if ((ike
->flags
& INPUTKEY_KEYPAD
) &&
177 !(wp
->screen
->mode
& MODE_KKEYPAD
))
179 if ((ike
->flags
& INPUTKEY_CURSOR
) &&
180 !(wp
->screen
->mode
& MODE_KCURSOR
))
183 if ((key
& KEYC_ESCAPE
) && (ike
->key
| KEYC_ESCAPE
) == key
)
188 if (i
== nitems(input_keys
)) {
189 log_debug2("key 0x%x missing", key
);
192 dlen
= strlen(ike
->data
);
193 log_debug2("found key 0x%x: \"%s\"", key
, ike
->data
);
195 /* Prefix a \033 for escape. */
196 if (key
& KEYC_ESCAPE
)
197 bufferevent_write(wp
->event
, "\033", 1);
198 bufferevent_write(wp
->event
, ike
->data
, dlen
);
201 /* Translate mouse and output. */
203 input_mouse(struct window_pane
*wp
, struct session
*s
, struct mouse_event
*m
)
207 struct paste_buffer
*pb
;
209 if (wp
->screen
->mode
& ALL_MOUSE_MODES
) {
211 * Use the SGR (1006) extension only if the application
212 * requested it and the underlying terminal also sent the event
213 * in this format (this is because an old style mouse release
214 * event cannot be converted into the new SGR format, since the
215 * released button is unknown). Otherwise pretend that tmux
216 * doesn't speak this extension, and fall back to the UTF-8
217 * (1005) extension if the application requested, or to the
220 if (m
->sgr
&& (wp
->screen
->mode
& MODE_MOUSE_SGR
)) {
221 len
= xsnprintf(buf
, sizeof buf
, "\033[<%d;%d;%d%c",
222 m
->sgr_xb
, m
->x
+ 1, m
->y
+ 1,
223 m
->sgr_rel
? 'm' : 'M');
224 } else if (wp
->screen
->mode
& MODE_MOUSE_UTF8
) {
225 len
= xsnprintf(buf
, sizeof buf
, "\033[M");
226 len
+= utf8_split2(m
->xb
+ 32, &buf
[len
]);
227 len
+= utf8_split2(m
->x
+ 33, &buf
[len
]);
228 len
+= utf8_split2(m
->y
+ 33, &buf
[len
]);
232 len
= xsnprintf(buf
, sizeof buf
, "\033[M");
233 buf
[len
++] = m
->xb
+ 32;
234 buf
[len
++] = m
->x
+ 33;
235 buf
[len
++] = m
->y
+ 33;
237 bufferevent_write(wp
->event
, buf
, len
);
241 if (m
->button
== 1 && (m
->event
& MOUSE_EVENT_CLICK
) &&
242 options_get_number(&wp
->window
->options
, "mode-mouse") == 1) {
243 pb
= paste_get_top(&global_buffers
);
245 paste_send_pane(pb
, wp
, "\r",
246 wp
->screen
->mode
& MODE_BRACKETPASTE
);
248 } else if ((m
->xb
& 3) != 1 &&
249 options_get_number(&wp
->window
->options
, "mode-mouse") == 1) {
250 if (window_pane_set_mode(wp
, &window_copy_mode
) == 0) {
251 window_copy_init_from_pane(wp
);
252 if (wp
->mode
->mouse
!= NULL
)
253 wp
->mode
->mouse(wp
, s
, m
);