2 * This program is free software; you can redistribute it and/or modify it
3 * under the terms of the GNU Lesser General Public License as published by
4 * the Free Software Foundation.
6 * This program is distributed in the hope that it will be useful, but
7 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
8 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
11 * You should have received a copy of the GNU Lesser General Public License
12 * along with this program; if not, see <http://www.gnu.org/licenses/>.
16 * Chris Lahey <clahey@ximian.com>
18 * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
28 #include <gdk/gdkkeysyms.h>
30 #include "e-text-event-processor-emacs-like.h"
32 static gint e_text_event_processor_emacs_like_event
33 (ETextEventProcessor
*tep
,
34 ETextEventProcessorEvent
*event
);
37 ETextEventProcessorEmacsLike
,
38 e_text_event_processor_emacs_like
,
39 E_TYPE_TEXT_EVENT_PROCESSOR
)
41 static const ETextEventProcessorCommand control_keys
[26] = {
42 { E_TEP_START_OF_LINE
, E_TEP_MOVE
, 0, "" }, /* a */
43 { E_TEP_BACKWARD_CHARACTER
, E_TEP_MOVE
, 0, "" }, /* b */
44 { E_TEP_SELECTION
, E_TEP_COPY
, 0, "" }, /* c */
45 { E_TEP_FORWARD_CHARACTER
, E_TEP_DELETE
, 0, "" }, /* d */
46 { E_TEP_END_OF_LINE
, E_TEP_MOVE
, 0, "" }, /* e */
47 { E_TEP_FORWARD_CHARACTER
, E_TEP_MOVE
, 0, "" }, /* f */
48 { E_TEP_SELECTION
, E_TEP_NOP
, 0, "" }, /* g */
49 { E_TEP_BACKWARD_CHARACTER
, E_TEP_DELETE
, 0, "" }, /* h */
50 { E_TEP_SELECTION
, E_TEP_NOP
, 0, "" }, /* i */
51 { E_TEP_SELECTION
, E_TEP_NOP
, 0, "" }, /* j */
52 { E_TEP_END_OF_LINE
, E_TEP_DELETE
, 0, "" }, /* k */
53 { E_TEP_SELECTION
, E_TEP_NOP
, 0, "" }, /* l */
54 { E_TEP_SELECTION
, E_TEP_NOP
, 0, "" }, /* m */
55 { E_TEP_FORWARD_LINE
, E_TEP_MOVE
, 0, "" }, /* n */
56 { E_TEP_SELECTION
, E_TEP_NOP
, 0, "" }, /* o */
57 { E_TEP_BACKWARD_LINE
, E_TEP_MOVE
, 0, "" }, /* p */
58 { E_TEP_SELECTION
, E_TEP_NOP
, 0, "" }, /* q */
59 { E_TEP_SELECTION
, E_TEP_NOP
, 0, "" }, /* r */
60 { E_TEP_SELECTION
, E_TEP_NOP
, 0, "" }, /* s */
61 { E_TEP_SELECTION
, E_TEP_NOP
, 0, "" }, /* t */
62 { E_TEP_START_OF_LINE
, E_TEP_DELETE
, 0, "" }, /* u */
63 { E_TEP_SELECTION
, E_TEP_PASTE
, 0, "" }, /* v */
64 { E_TEP_SELECTION
, E_TEP_NOP
, 0, "" }, /* w */
65 { E_TEP_SELECTION
, E_TEP_DELETE
, 0, "" }, /* x */
66 { E_TEP_SELECTION
, E_TEP_PASTE
, 0, "" }, /* y */
67 { E_TEP_SELECTION
, E_TEP_NOP
, 0, "" } /* z */
70 static const ETextEventProcessorCommand alt_keys
[26] = {
71 { E_TEP_SELECTION
, E_TEP_NOP
, 0, "" }, /* a */
72 { E_TEP_BACKWARD_WORD
, E_TEP_MOVE
, 0, "" }, /* b */
73 { E_TEP_SELECTION
, E_TEP_CAPS
, E_TEP_CAPS_TITLE
, "" },/* c */
74 { E_TEP_FORWARD_WORD
, E_TEP_DELETE
, 0, "" }, /* d */
75 { E_TEP_SELECTION
, E_TEP_NOP
, 0, "" }, /* e */
76 { E_TEP_FORWARD_WORD
, E_TEP_MOVE
, 0, "" }, /* f */
77 { E_TEP_SELECTION
, E_TEP_NOP
, 0, "" }, /* g */
78 { E_TEP_SELECTION
, E_TEP_NOP
, 0, "" }, /* h */
79 { E_TEP_SELECTION
, E_TEP_NOP
, 0, "" }, /* i */
80 { E_TEP_SELECTION
, E_TEP_NOP
, 0, "" }, /* j */
81 { E_TEP_SELECTION
, E_TEP_NOP
, 0, "" }, /* k */
82 { E_TEP_SELECTION
, E_TEP_CAPS
, E_TEP_CAPS_LOWER
, "" }, /* l */
83 { E_TEP_SELECTION
, E_TEP_NOP
, 0, "" }, /* m */
84 { E_TEP_SELECTION
, E_TEP_NOP
, 0, "" }, /* n */
85 { E_TEP_SELECTION
, E_TEP_NOP
, 0, "" }, /* o */
86 { E_TEP_SELECTION
, E_TEP_NOP
, 0, "" }, /* p */
87 { E_TEP_SELECTION
, E_TEP_NOP
, 0, "" }, /* q */
88 { E_TEP_SELECTION
, E_TEP_NOP
, 0, "" }, /* r */
89 { E_TEP_SELECTION
, E_TEP_NOP
, 0, "" }, /* s */
90 { E_TEP_SELECTION
, E_TEP_NOP
, 0, "" }, /* t */
91 { E_TEP_SELECTION
, E_TEP_CAPS
, E_TEP_CAPS_UPPER
, "" }, /* u */
92 { E_TEP_SELECTION
, E_TEP_NOP
, 0, "" }, /* v */
93 { E_TEP_SELECTION
, E_TEP_NOP
, 0, "" }, /* w */
94 { E_TEP_SELECTION
, E_TEP_NOP
, 0, "" }, /* x */
95 { E_TEP_SELECTION
, E_TEP_NOP
, 0, "" }, /* y */
96 { E_TEP_SELECTION
, E_TEP_NOP
, 0, "" } /* z */
101 e_text_event_processor_emacs_like_class_init (ETextEventProcessorEmacsLikeClass
*class)
103 ETextEventProcessorClass
*processor_class
;
105 processor_class
= (ETextEventProcessorClass
*) class;
107 processor_class
->event
= e_text_event_processor_emacs_like_event
;
111 e_text_event_processor_emacs_like_init (ETextEventProcessorEmacsLike
*tep
)
116 e_text_event_processor_emacs_like_event (ETextEventProcessor
*tep
,
117 ETextEventProcessorEvent
*event
)
119 ETextEventProcessorCommand command
;
120 ETextEventProcessorEmacsLike
*tep_el
= E_TEXT_EVENT_PROCESSOR_EMACS_LIKE (tep
);
121 command
.action
= E_TEP_NOP
;
123 /* Warning from the Intel compiler here:
124 * e-text-event-processor-emacs-like.c(136): warning #589:
125 * transfer of control bypasses initialization of:
126 * variable "key" (declared at line 194)
127 * switch (event->type) {
130 switch (event
->type
) {
131 case GDK_BUTTON_PRESS
:
132 if (event
->button
.button
== 1 || event
->button
.button
== 2) {
133 command
.action
= E_TEP_GRAB
;
134 command
.device
= event
->button
.device
;
135 command
.time
= event
->button
.time
;
136 g_signal_emit_by_name (tep
, "command", &command
);
137 if (event
->button
.button
== 1 && event
->button
.state
& GDK_SHIFT_MASK
)
138 command
.action
= E_TEP_SELECT
;
140 command
.action
= E_TEP_MOVE
;
141 command
.position
= E_TEP_VALUE
;
142 command
.value
= event
->button
.position
;
143 command
.time
= event
->button
.time
;
144 tep_el
->mouse_down
= event
->button
.button
== 1;
148 case GDK_2BUTTON_PRESS
:
149 if (event
->button
.button
== 1) {
150 command
.action
= E_TEP_SELECT
;
151 command
.position
= E_TEP_SELECT_WORD
;
152 command
.time
= event
->button
.time
;
156 case GDK_3BUTTON_PRESS
:
157 if (event
->button
.button
== 1) {
158 command
.action
= E_TEP_SELECT
;
159 command
.position
= E_TEP_SELECT_ALL
;
160 command
.time
= event
->button
.time
;
164 case GDK_BUTTON_RELEASE
:
165 if (event
->button
.button
== 1) {
166 command
.action
= E_TEP_UNGRAB
;
167 command
.time
= event
->button
.time
;
168 tep_el
->mouse_down
= FALSE
;
169 } else if (event
->button
.button
== 2) {
170 command
.action
= E_TEP_MOVE
;
171 command
.position
= E_TEP_VALUE
;
172 command
.value
= event
->button
.position
;
173 command
.time
= event
->button
.time
;
174 g_signal_emit_by_name (tep
, "command", &command
);
176 command
.action
= E_TEP_GET_SELECTION
;
177 command
.position
= E_TEP_SELECTION
;
179 command
.time
= event
->button
.time
;
183 case GDK_MOTION_NOTIFY
:
184 if (tep_el
->mouse_down
) {
185 command
.action
= E_TEP_SELECT
;
186 command
.position
= E_TEP_VALUE
;
187 command
.time
= event
->motion
.time
;
188 command
.value
= event
->motion
.position
;
194 ETextEventProcessorEventKey key
= event
->key
;
196 command
.time
= event
->key
.time
;
198 if (key
.state
& GDK_SHIFT_MASK
)
199 command
.action
= E_TEP_SELECT
;
200 else if (key
.state
& GDK_MOD1_MASK
)
201 command
.action
= E_TEP_NOP
;
203 command
.action
= E_TEP_MOVE
;
205 switch (key
.keyval
) {
207 case GDK_KEY_KP_Home
:
208 if (key
.state
& GDK_CONTROL_MASK
)
209 command
.position
= E_TEP_START_OF_BUFFER
;
211 command
.position
= E_TEP_START_OF_LINE
;
216 if (key
.state
& GDK_CONTROL_MASK
)
217 command
.position
= E_TEP_END_OF_BUFFER
;
219 command
.position
= E_TEP_END_OF_LINE
;
222 case GDK_KEY_Page_Up
:
223 case GDK_KEY_KP_Page_Up
:
224 command
.position
= E_TEP_BACKWARD_PAGE
;
227 case GDK_KEY_Page_Down
:
228 case GDK_KEY_KP_Page_Down
:
229 command
.position
= E_TEP_FORWARD_PAGE
;
232 /* CUA has Ctrl-Up/Ctrl-Down as paragraph up down */
235 command
.position
= E_TEP_BACKWARD_LINE
;
239 case GDK_KEY_KP_Down
:
240 command
.position
= E_TEP_FORWARD_LINE
;
244 case GDK_KEY_KP_Left
:
245 if (key
.state
& GDK_CONTROL_MASK
)
246 command
.position
= E_TEP_BACKWARD_WORD
;
248 command
.position
= E_TEP_BACKWARD_CHARACTER
;
252 case GDK_KEY_KP_Right
:
253 if (key
.state
& GDK_CONTROL_MASK
)
254 command
.position
= E_TEP_FORWARD_WORD
;
256 command
.position
= E_TEP_FORWARD_CHARACTER
;
259 case GDK_KEY_BackSpace
:
260 command
.action
= E_TEP_DELETE
;
261 if (key
.state
& GDK_CONTROL_MASK
)
262 command
.position
= E_TEP_BACKWARD_WORD
;
264 command
.position
= E_TEP_BACKWARD_CHARACTER
;
268 command
.action
= E_TEP_DELETE
;
269 command
.position
= E_TEP_END_OF_LINE
;
273 case GDK_KEY_KP_Insert
:
274 if (key
.state
& GDK_SHIFT_MASK
) {
275 command
.action
= E_TEP_PASTE
;
276 command
.position
= E_TEP_SELECTION
;
277 } else if (key
.state
& GDK_CONTROL_MASK
) {
278 command
.action
= E_TEP_COPY
;
279 command
.position
= E_TEP_SELECTION
;
281 /* gtk_toggle_insert(text) -- IMPLEMENT -- FIXME */
286 command
.action
= E_TEP_COPY
;
287 command
.position
= E_TEP_SELECTION
;
291 command
.action
= E_TEP_PASTE
;
292 command
.position
= E_TEP_SELECTION
;
296 command
.action
= E_TEP_COPY
;
297 command
.position
= E_TEP_SELECTION
;
298 g_signal_emit_by_name (
299 tep
, "command", &command
);
301 command
.action
= E_TEP_DELETE
;
302 command
.position
= E_TEP_SELECTION
;
306 case GDK_KEY_KP_Delete
:
307 if (key
.state
& GDK_CONTROL_MASK
) {
308 command
.action
= E_TEP_DELETE
;
309 command
.position
= E_TEP_FORWARD_WORD
;
310 } else if (key
.state
& GDK_SHIFT_MASK
) {
311 command
.action
= E_TEP_COPY
;
312 command
.position
= E_TEP_SELECTION
;
313 g_signal_emit_by_name (
314 tep
, "command", &command
);
316 command
.action
= E_TEP_DELETE
;
317 command
.position
= E_TEP_SELECTION
;
319 command
.action
= E_TEP_DELETE
;
320 command
.position
= E_TEP_FORWARD_CHARACTER
;
326 case GDK_KEY_ISO_Left_Tab
:
327 case GDK_KEY_3270_BackTab
:
328 /* Don't insert literally */
329 command
.action
= E_TEP_NOP
;
330 command
.position
= E_TEP_SELECTION
;
334 case GDK_KEY_KP_Enter
:
335 if (tep
->allow_newlines
) {
336 if (key
.state
& GDK_CONTROL_MASK
) {
337 command
.action
= E_TEP_ACTIVATE
;
338 command
.position
= E_TEP_SELECTION
;
340 command
.action
= E_TEP_INSERT
;
341 command
.position
= E_TEP_SELECTION
;
343 command
.string
= "\n";
346 if (key
.state
& GDK_CONTROL_MASK
) {
347 command
.action
= E_TEP_NOP
;
348 command
.position
= E_TEP_SELECTION
;
350 command
.action
= E_TEP_ACTIVATE
;
351 command
.position
= E_TEP_SELECTION
;
357 /* Don't insert literally */
358 command
.action
= E_TEP_NOP
;
359 command
.position
= E_TEP_SELECTION
;
362 case GDK_KEY_KP_Space
:
363 command
.action
= E_TEP_INSERT
;
364 command
.position
= E_TEP_SELECTION
;
366 command
.string
= " ";
369 case GDK_KEY_KP_Equal
:
370 command
.action
= E_TEP_INSERT
;
371 command
.position
= E_TEP_SELECTION
;
373 command
.string
= "=";
376 case GDK_KEY_KP_Multiply
:
377 command
.action
= E_TEP_INSERT
;
378 command
.position
= E_TEP_SELECTION
;
380 command
.string
= "*";
384 command
.action
= E_TEP_INSERT
;
385 command
.position
= E_TEP_SELECTION
;
387 command
.string
= "+";
390 case GDK_KEY_KP_Subtract
:
391 command
.action
= E_TEP_INSERT
;
392 command
.position
= E_TEP_SELECTION
;
394 command
.string
= "-";
397 case GDK_KEY_KP_Decimal
:
398 command
.action
= E_TEP_INSERT
;
399 command
.position
= E_TEP_SELECTION
;
401 command
.string
= ".";
404 case GDK_KEY_KP_Divide
:
405 command
.action
= E_TEP_INSERT
;
406 command
.position
= E_TEP_SELECTION
;
408 command
.string
= "/";
412 command
.action
= E_TEP_INSERT
;
413 command
.position
= E_TEP_SELECTION
;
415 command
.string
= "0";
419 command
.action
= E_TEP_INSERT
;
420 command
.position
= E_TEP_SELECTION
;
422 command
.string
= "1";
426 command
.action
= E_TEP_INSERT
;
427 command
.position
= E_TEP_SELECTION
;
429 command
.string
= "2";
433 command
.action
= E_TEP_INSERT
;
434 command
.position
= E_TEP_SELECTION
;
436 command
.string
= "3";
440 command
.action
= E_TEP_INSERT
;
441 command
.position
= E_TEP_SELECTION
;
443 command
.string
= "4";
447 command
.action
= E_TEP_INSERT
;
448 command
.position
= E_TEP_SELECTION
;
450 command
.string
= "5";
454 command
.action
= E_TEP_INSERT
;
455 command
.position
= E_TEP_SELECTION
;
457 command
.string
= "6";
461 command
.action
= E_TEP_INSERT
;
462 command
.position
= E_TEP_SELECTION
;
464 command
.string
= "7";
468 command
.action
= E_TEP_INSERT
;
469 command
.position
= E_TEP_SELECTION
;
471 command
.string
= "8";
475 command
.action
= E_TEP_INSERT
;
476 command
.position
= E_TEP_SELECTION
;
478 command
.string
= "9";
482 if ((key
.state
& GDK_CONTROL_MASK
) &&
483 !(key
.state
& GDK_MOD1_MASK
)) {
484 if ((key
.keyval
>= 'A') && (key
.keyval
<= 'Z'))
485 key
.keyval
-= 'A' - 'a';
487 if ((key
.keyval
>= 'a') && (key
.keyval
<= 'z')) {
488 command
.position
= control_keys
[(gint
) (key
.keyval
- 'a')].position
;
489 if (control_keys
[(gint
) (key
.keyval
- 'a')].action
!= E_TEP_MOVE
)
490 command
.action
= control_keys
[(gint
) (key
.keyval
- 'a')].action
;
491 command
.value
= control_keys
[(gint
) (key
.keyval
- 'a')].value
;
492 command
.string
= control_keys
[(gint
) (key
.keyval
- 'a')].string
;
495 if (key
.keyval
== ' ') {
496 command
.action
= E_TEP_NOP
;
499 if (key
.keyval
== 'x') {
500 command
.action
= E_TEP_COPY
;
501 command
.position
= E_TEP_SELECTION
;
502 g_signal_emit_by_name (tep
, "command", &command
);
504 command
.action
= E_TEP_DELETE
;
505 command
.position
= E_TEP_SELECTION
;
510 } else if ((key
.state
& GDK_MOD1_MASK
) &&
511 !(key
.state
& GDK_CONTROL_MASK
)) {
512 if ((key
.keyval
>= 'A') && (key
.keyval
<= 'Z'))
513 key
.keyval
-= 'A' - 'a';
515 if ((key
.keyval
>= 'a') && (key
.keyval
<= 'z')) {
516 command
.position
= alt_keys
[(gint
) (key
.keyval
- 'a')].position
;
517 if (alt_keys
[(gint
) (key
.keyval
- 'a')].action
!= E_TEP_MOVE
)
518 command
.action
= alt_keys
[(gint
) (key
.keyval
- 'a')].action
;
519 command
.value
= alt_keys
[(gint
) (key
.keyval
- 'a')].value
;
520 command
.string
= alt_keys
[(gint
) (key
.keyval
- 'a')].string
;
522 } else if (!(key
.state
& GDK_MOD1_MASK
) &&
523 !(key
.state
& GDK_CONTROL_MASK
) &&
525 if (key
.keyval
>= GDK_KEY_KP_0
&&
526 key
.keyval
<= GDK_KEY_KP_9
) {
530 command
.action
= E_TEP_INSERT
;
531 command
.position
= E_TEP_SELECTION
;
532 command
.value
= strlen (key
.string
);
533 command
.string
= key
.string
;
536 command
.action
= E_TEP_NOP
;
541 case GDK_KEY_RELEASE
:
542 command
.time
= event
->key
.time
;
543 command
.action
= E_TEP_NOP
;
547 command
.action
= E_TEP_NOP
;
552 if (command
.action
!= E_TEP_NOP
) {
553 g_signal_emit_by_name (tep
, "command", &command
);
559 ETextEventProcessor
*
560 e_text_event_processor_emacs_like_new (void)
562 return g_object_new (E_TYPE_TEXT_EVENT_PROCESSOR_EMACS_LIKE
, NULL
);