1
2 /******************************************************************************
3 * MODULE : edit_keyboard.cpp
4 * DESCRIPTION: Keyboard handling
5 * COPYRIGHT : (C) 1999 Joris van der Hoeven
6 *******************************************************************************
7 * This software falls under the GNU general public license version 3 or later.
8 * It comes WITHOUT ANY WARRANTY WHATSOEVER. For details, see the file LICENSE
9 * in the root directory or <http://www.gnu.org/licenses/gpl-3.0.html>.
10 ******************************************************************************/
11
12 #include "edit_interface.hpp"
13 #include "analyze.hpp"
14 #include "tm_buffer.hpp"
15 #include "archiver.hpp"
16
17 /******************************************************************************
18 * Basic subroutines for keyboard handling
19 ******************************************************************************/
20
21 int
get_input_mode()22 edit_interface_rep::get_input_mode () {
23 return input_mode;
24 }
25
26 void
set_input_mode(int mode)27 edit_interface_rep::set_input_mode (int mode) {
28 interrupt_shortcut ();
29 // avoids keyboard shortcuts when using the menu between two keystrokes
30
31 if ((mode == INPUT_NORMAL) && (input_mode != INPUT_NORMAL)) {
32 selection_cancel ();
33 completions= array<string> ();
34 }
35 input_mode= mode;
36 }
37
38 void
set_input_normal()39 edit_interface_rep::set_input_normal () {
40 set_input_mode (INPUT_NORMAL);
41 }
42
43 bool
in_normal_mode()44 edit_interface_rep::in_normal_mode () {
45 return input_mode == INPUT_NORMAL;
46 }
47
48 bool
in_search_mode()49 edit_interface_rep::in_search_mode () {
50 return input_mode == INPUT_SEARCH;
51 }
52
53 bool
in_replace_mode()54 edit_interface_rep::in_replace_mode () {
55 return input_mode == INPUT_REPLACE;
56 }
57
58 bool
in_spell_mode()59 edit_interface_rep::in_spell_mode () {
60 return input_mode == INPUT_SPELL;
61 }
62
63 bool
kbd_get_command(string which,string & help,command & c)64 edit_interface_rep::kbd_get_command (string which, string& help, command& c) {
65 return sv->kbd_get_command (which, help, c);
66 }
67
68 /******************************************************************************
69 * Main keyboard routines
70 ******************************************************************************/
71
72 void
interrupt_shortcut()73 edit_interface_rep::interrupt_shortcut () {
74 if (sh_mark != 0) mark_end (sh_mark);
75 sh_s= "";
76 sh_mark= 0;
77 }
78
79 bool
try_shortcut(string comb)80 edit_interface_rep::try_shortcut (string comb) {
81 int status;
82 command cmd;
83 string shorth;
84 string help;
85
86 sv->get_keycomb (comb, status, cmd, shorth, help);
87 //cout << "Try " << comb << " -> " << shorth << ", " << help
88 //<< "; " << sh_mark << ", " << status << "\n";
89 if (status != 0) {
90 if (status >= 3) {
91 interrupt_shortcut ();
92 status -= 3;
93 if (status == 0) return false;
94 }
95 else {
96 if (sh_mark != 0 && !mark_cancel (sh_mark)) {
97 sh_mark= 0;
98 return false;
99 }
100 }
101 sh_s= comb;
102 sh_mark= new_marker ();
103 mark_start (sh_mark);
104 archive_state ();
105 string rew_s= sv->kbd_post_rewrite (sh_s);
106 tree rew= sv->kbd_system_rewrite (rew_s);
107 if (N(help)>0) set_message (help, rew);
108 tree rhs= (shorth == rew_s? tree (""): sv->kbd_system_rewrite (shorth));
109 //cout << "Shortcut: " << sh_s << " -> " << rew << "\n";
110 if ((search_forwards (" ", comb) >= 0 && comb != " ") ||
111 (search_forwards ("-", comb) >= 0 && comb != "-")) {
112 tree t= rhs;
113 if (is_compound (t, "render-key", 1)) t= t[0];
114 if (is_func (t, WITH)) t= t[N(t)-1];
115 string r= as_string (t);
116 if (starts (r, "<") && !starts (r, "<#"))
117 if (cork_to_utf8 (r) != r)
118 rhs= tree (CONCAT, rhs, " (" * r(1, N(r)-1) * ")");
119 call ("set-temporary-message",
120 tree (CONCAT, "keyboard shortcut: ", rew), rhs,
121 shorth == ""? 1: 3000);
122 }
123 if ((status & 1) == 1) cmd ();
124 else if (N(shorth) > 0) call ("kbd-insert", shorth);
125 //cout << "Mark= " << sh_mark << "\n";
126 return true;
127 }
128
129 return false;
130 }
131
132 void
key_press(string gkey)133 edit_interface_rep::key_press (string gkey) {
134 string zero= "a"; zero[0]= '\0';
135 string key= replace (gkey, "<#0>", zero);
136 if (pre_edit_mark != 0) {
137 ASSERT (sh_mark == 0, "invalid shortcut during pre-edit");
138 mark_cancel (pre_edit_mark);
139 pre_edit_s= "";
140 pre_edit_mark= 0;
141 }
142 if (starts (key, "pre-edit:") ) {
143 interrupt_shortcut ();
144 string s= key (9, N(key));
145 if (s == "") return;
146 int i, n= N(s), pos= N(s);
147 for (i=0; i<n; i++)
148 if (s[i] == ':' && is_int (s (0, i))) {
149 int k= as_int (s (0, i));
150 s= s (i+1, n);
151 pos= 0;
152 for (int j=0; j<k && pos<N(s); j++)
153 tm_char_forwards (s, pos);
154 break;
155 }
156 pre_edit_s= s;
157 pre_edit_mark= new_marker ();
158 mark_start (pre_edit_mark);
159 archive_state ();
160 insert_tree (compound ("pre-edit", s), path (0, pos));
161 return;
162 }
163
164 string new_sh= N(sh_s)==0? key: sh_s * " " * key;
165 if (try_shortcut (new_sh)) return;
166 if (new_sh != key) {
167 interrupt_shortcut ();
168 if (try_shortcut (key)) return;
169 }
170
171 string rew= sv->kbd_post_rewrite (key);
172 if (N(rew) == 1) {
173 int i ((unsigned char) rew[0]);
174 if ((i >= 32 && i <= 127) || (i >= 128 && i <= 255) || (i == 25))
175 if (!inside_active_graphics ()) {
176 archive_state ();
177 call ("kbd-insert", rew);
178 }
179 interrupt_shortcut ();
180 }
181 else if (contains_unicode_char (rew)) {
182 archive_state ();
183 call ("kbd-insert", key);
184 interrupt_shortcut ();
185 }
186 else if (DEBUG_KEYBOARD)
187 debug_keyboard
188 << "unrecognized key " << key << ". "
189 << "Undefined shortcut or key missing in the encoding files.\n";
190 }
191
192 void
emulate_keyboard(string keys,string action)193 edit_interface_rep::emulate_keyboard (string keys, string action) {
194 string s= keys;
195 while (s != "") {
196 int i;
197 for (i=1; i<N(s); i++)
198 if (s[i]==' ') break;
199 call ("keyboard-press", object (s (0, i)), object ((double) 0));
200 if (i<N(s)) i++;
201 s= s (i, N(s));
202 }
203 if (N (action) != 0)
204 set_message (concat ("You can also obtain ", action, " by typing ", keys),
205 action);
206 }
207
208 /******************************************************************************
209 * Retrieving keyboard shortcuts
210 ******************************************************************************/
211
212 tree
kbd(string s)213 edit_interface_rep::kbd (string s) {
214 return sv->kbd_system_rewrite (s);
215 }
216
217 tree
kbd_shortcut(string cmd)218 edit_interface_rep::kbd_shortcut (string cmd) {
219 string s= as_string (eval ("(kbd-find-inv-binding '" * cmd * ")"));
220 return kbd (s);
221 }
222
223 /******************************************************************************
224 * Event handlers
225 ******************************************************************************/
226
227 void
handle_keypress(string key,time_t t)228 edit_interface_rep::handle_keypress (string key, time_t t) {
229 bool started= false;
230 #ifdef USE_EXCEPTIONS
231 try {
232 #endif
233 if (DEBUG_KEYBOARD) {
234 //for (int i=0; i<N(key); i++)
235 // cout << ((int) (unsigned char) key[i]) << " ";
236 //cout << "\n";
237 debug_keyboard << "Pressed " << key << " at " << t << "\n";
238 }
239 //time_t t1= texmacs_time ();
240 if (is_nil (eb)) apply_changes ();
241 start_editing ();
242 started= true;
243 string zero= "a"; zero[0]= '\0';
244 string gkey= replace (key, zero, "<#0>");
245 call ("keyboard-press", object (gkey), object ((double) t));
246 update_focus_loci ();
247 if (!is_nil (focus_ids))
248 call ("link-follow-ids", object (focus_ids), object ("focus"));
249 notify_change (THE_DECORATIONS);
250 end_editing ();
251 //time_t t2= texmacs_time ();
252 //if (t2 - t1 >= 10) cout << "handle_keypress took " << t2-t1 << "ms\n";
253 #ifdef USE_EXCEPTIONS
254 }
255 catch (string msg) {
256 if (started) {
257 cancel_editing ();
258 interrupt_shortcut ();
259 }
260 }
261 handle_exceptions ();
262 #endif
263 }
264
265 void drag_left_reset ();
266 void drag_right_reset ();
267
268 void
handle_keyboard_focus(bool has_focus,time_t t)269 edit_interface_rep::handle_keyboard_focus (bool has_focus, time_t t) {
270 if (DEBUG_KEYBOARD) {
271 if (has_focus) debug_keyboard << "Got focus at " << t << "\n";
272 else debug_keyboard << "Lost focus at " << t << "\n";
273 }
274 if (got_focus != has_focus) {
275 drag_left_reset ();
276 drag_right_reset ();
277 }
278 got_focus= has_focus; (void) t;
279 notify_change (THE_FOCUS);
280 if (got_focus) {
281 focus_on_this_editor ();
282 notify_change (THE_DECORATIONS);
283 }
284 call ("keyboard-focus", object (has_focus), object ((double) t));
285 }
286