1 /**********************************************************
2 ** Events.c : Process events coming from main window and **
3 ** public port. Written by T.Pierron and C.Guillaume. **
4 ** Free software under terms of GNU license. 12 nov 2000 **
5 **********************************************************/
7 #include <intuition/intuition.h> /* Std types */
8 #include <devices/inputevent.h> /* For raw keymap conversion */
9 #include <libraries/asl.h>
14 #include "IPC_Prefs.h"
20 #include "ProtoTypes.h"
22 #define CATCOMP_NUMBERS /* String ID for ErrMsg() */
26 #include <aros/debug.h>
28 static struct InputEvent ie
= {0,IECLASS_RAWKEY
}; /* Keyboard translation map */
29 extern struct IntuiMessage msgbuf
;
32 struct FileRequester
*fr
;
36 /*** Process keyboard events ***/
37 void handle_kbd(Project p
)
39 static UBYTE buffer
[8], shift
;
41 /* Look is rawkey can be processed, thus doesn't translate it */
42 if(msgbuf
.Code
> 0x7E) { record
|= 0x80; return; }
44 /* Look if keypad should be processed as a PC one */
45 if( (*buffer
= (msgbuf
.Qualifier
& IEQUALIFIER_NUMERICPAD
&& msgbuf
.Code
>= N0_KEY
&&
46 msgbuf
.Code
<= N9_KEY
&& (prefs
.xtend
|| msgbuf
.Qualifier
& CTRLKEYS
)))
48 /* Clear CONTROL qualifier, if no PC keypad emulation */
49 msgbuf
.Qualifier
&= ~CTRLKEYS
;
51 shift
= (msgbuf
.Qualifier
& SHIFTKEYS
? 1 : 0);
57 /* Switch with replacement cursor */
58 p
->cursmode
= !p
->cursmode
;
59 inv_curs(p
, FALSE
); inv_curs(p
, TRUE
);
62 case N1_KEY
: if( *buffer
) { horiz_pos(p
,MAXPOS
); return; } break;
63 case N3_KEY
: if( *buffer
) { pg_updown(p
, 1); return; } break;
64 case N7_KEY
: if( *buffer
) { horiz_pos(p
, 0); return; } break;
65 case N9_KEY
: if( *buffer
) { pg_updown(p
,-1); return; } break;
67 /* Amiga space indent line */
68 if( msgbuf
.Qualifier
& AMIGAKEYS
) {
69 indent_by(p
, ' ', shift
? -1:1); return;
72 if( msgbuf
.Qualifier
& AMIGAKEYS
) {
73 indent_by(p
, '\t',shift
? -1:1); return;
78 else if( msgbuf
.Qualifier
& AMIGAKEYS
)
83 back_space(p
, (msgbuf
.Qualifier
& ALTKEYS
) != 0);
86 /* Pressing ESC key while text is selected, unmark all **
87 ** otherwise we want to add the escape character */
88 if(p
->ccp
.select
==0) break;
89 unmark_all(p
,TRUE
); return;
90 case NPERIOD_KEY
: if( *buffer
== 0 ) break;
97 del(p
, (msgbuf
.Qualifier
& ALTKEYS
) != 0);
99 case N8_KEY
: if( *buffer
== 0 ) break;
101 if( msgbuf
.Qualifier
& CTRLKEYS
)
102 move_to_line(p
,0,LINE_AS_IS
);
104 if( msgbuf
.Qualifier
& ALTKEYS
)
111 case N2_KEY
: if( *buffer
== 0 ) break;
113 if( msgbuf
.Qualifier
& CTRLKEYS
)
114 move_to_line(p
,p
->max_lines
-1,LINE_AS_IS
);
116 if( msgbuf
.Qualifier
& ALTKEYS
)
123 case N6_KEY
: if( *buffer
== 0 ) break;
124 case RIGHT_KEY
: /* Used for various things! */
125 if( msgbuf
.Qualifier
& CTRLKEYS
)
127 edit
= select_panel(edit
, NEXT_PROJECT
);
131 if( msgbuf
.Qualifier
& ALTKEYS
)
132 scroll_xdelta(p
, gui
.xstep
);
136 curs_right(p
, (msgbuf
.Qualifier
& ALTKEYS
) != 0);
138 case N4_KEY
: if( *buffer
== 0 ) break;
140 if( msgbuf
.Qualifier
& CTRLKEYS
)
142 edit
= select_panel(edit
, PREV_PROJECT
);
146 if( msgbuf
.Qualifier
& ALTKEYS
)
147 scroll_xdelta(p
, -gui
.xstep
);
151 curs_left(p
, (msgbuf
.Qualifier
& ALTKEYS
) != 0);
155 if( msgbuf
.Qualifier
& CTRLKEYS
)
157 STRPTR path
= GetIncludeFile(p
, p
->edited
);
160 if(NULL
!= path
&& (shift
== 0 || warn_modif(edit
)))
161 new = load_and_activate(edit
, path
, shift
);
169 case PGDOWN_KEY
: pg_updown(p
, 1); return;
170 case PGUP_KEY
: pg_updown(p
, -1); return;
173 if( msgbuf
.Qualifier
& CTRLKEYS
) move_to_line(p
,0,LINE_AS_IS
);
177 if( msgbuf
.Qualifier
& CTRLKEYS
) move_to_line(p
,p
->max_lines
-1,LINE_AS_IS
);
178 else horiz_pos(p
,MAXPOS
);
181 case RAWKEY_NM_WHEEL_UP
:
182 scroll_ydelta(p
, -3);
185 case RAWKEY_NM_WHEEL_DOWN
:
190 // Changed from DEBUG to DEBUG_EDIT to avoid conflicts with <aros/debug.h>
193 printf("mask = 0x%02x\n", RP
->Mask
); return;
195 show_modifs(&p
->undo
); return;
197 show_modifs(&p
->redo
); return;
201 /* Translate key (with dead one) using keymap library */
202 ie
.ie_Code
= msgbuf
.Code
;
203 ie
.ie_EventAddress
= *((APTR
*)msgbuf
.IAddress
);
205 /* Look if CTRL qualifier is used */
206 if( msgbuf
.Qualifier
& (CTRLKEYS
|AMIGAKEYS
) )
208 /* Discard qualifiers, if CTRL+<a-z> is pressed a control char will **
209 ** be returned, which does not reflect the key we want to process. */
210 ie
.ie_Qualifier
= msgbuf
.Qualifier
& ~(CTRLKEYS
| AMIGAKEYS
| IEQUALIFIER_CAPSLOCK
);
212 /* If it's not a known shortcut, insert control char instead */
213 if(MapRawKey(&ie
, buffer
, 8, NULL
) > 0)
215 if( msgbuf
.Qualifier
& AMIGAKEYS
)
217 /* This is too annoying to insert into menus: Amiga+2~9 enable **
218 ** to quickly change tabstop of current project (not in prefs) */
219 if( '2' <= *buffer
&& *buffer
<= '9' )
221 WORD tabstop
= *buffer
- '0';
222 if(tabstop
!= p
->tabsize
)
223 p
->tabsize
= tabstop
, inv_curs(p
, FALSE
),
224 active_project(p
, FALSE
);
228 /* CTRL + `1' ~ `0' => activate project nb. x */
229 else if( '0' <= *buffer
&& *buffer
<= '9' )
231 edit
= select_panel(edit
,*buffer
== '0' ? -10 : '0' - *buffer
);
236 case '\\':change_case(p
, 0); return;
237 case '/': change_case(p
, 1); return;
238 case 'j': join_strip(p
); return;
239 case 'n': FindPattern(p
, 1); return;
240 case 'p': FindPattern(p
,-1); return;
241 case 'q': handle_menu(111); return;
242 case 'Q': handle_menu(113); return;
243 case 'r': ReplacePattern(p
); return;
244 case 'R': ReplaceAllPat(p
); return;
245 case 's': FindWord(p
, 1); return;
246 case 'S': FindWord(p
,-1); return;
247 case 'z': last_modif(&p
->undo
, 0); return;
248 case '[': handle_menu(401); return;
249 case ']': handle_menu(402); return;
254 /* Make sure this time qualifiers are taken into account */
255 ie
.ie_Qualifier
= msgbuf
.Qualifier
;
257 /* Map RAWKEY to ANSI (dead keys return 0) */
258 if(MapRawKey(&ie
, buffer
, 8, NULL
) > 0)
260 /* register UBYTE code = *buffer; */
262 /* Inserting one char is the most common operation **
263 ** and therefore needs to be highly optimized: */
264 if( add_char(&p
->undo
, p
->edited
, p
->nbc
, *buffer
) )
267 curs_right(p
, FALSE
);
268 } else ThrowError(Wnd
, ErrMsg(ERR_NOMEM
));
270 if(record
) reg_act_addchar( *buffer
), record
|= 0x80;
274 /*** Handle menu related events ***/
275 void handle_menu( LONG MenuID
)
279 shift
= (msgbuf
.Qualifier
& SHIFTKEYS
? 1 : 0);
283 case 101: /* New file */
286 if( ( new = new_project(edit
, &prefs
) ) )
288 /* Compute panel tabs size */
289 inv_curs(edit
, FALSE
);
291 active_project(edit
=new, TRUE
);
293 } else ThrowError(Wnd
, ErrMsg(ERR_NOMEM
));
296 case 102: /* Split open */
298 /* Ask a new file name, using the same working directory as current document */
299 if(NULL
!= (fr
= (struct FileRequester
*) ask_load(Wnd
, (AskArgs
*)&edit
->path
, FALSE
, GetMenuText(102))))
303 /* Use current project if it is empty and unmodified */
304 if( (new = load_and_activate_fr(edit
, (APTR
) fr
, (edit
->path
== NULL
&& (edit
->state
& MODIFIED
) == 0) ? 2 : 3) ) )
308 case 103: /* Open (in current panel) */
309 if( warn_modif(edit
) )
314 if(NULL
!= (path
= ask_load(Wnd
, (AskArgs
*)&edit
->path
, TRUE
, GetMenuText(103))))
316 load_and_activate(edit
, path
, 1);
319 else reload_project( edit
);
322 if(0 == shift
) goto case_sav
;
324 case 106: save_project (edit
,TRUE
,TRUE
); break; /* Save as */
325 case_sav
: save_project (edit
,TRUE
,FALSE
); break; /* Save one file */
326 case 107: save_projects(edit
,FALSE
); break; /* Save changes */
327 case 108: print_project (edit
); break; /* Print project */
328 case 109: show_info(edit
); break; /* Information */
330 case 113: /* Save if necessary, then quit */
331 if((edit
->state
& MODIFIED
) && save_project(edit
, TRUE
, FALSE
) == 0)
333 case 111: /* Close project */
334 { Project
new = edit
->prev
;
335 if(new == NULL
) new = edit
->next
;
336 /* Check if there were modifications */
337 if( close_project(edit
) )
339 /* If there is another opened project, shows it */
340 inv_curs(edit
,FALSE
); FreeVec(edit
);
343 active_project(edit
= new, FALSE
);
345 /* Otherwise quits */
350 /* Modified project not yet saved */
351 inv_curs(edit
, FALSE
);
352 if(NULL
!= (edit
= (shift
? save_projects(edit
, TRUE
) : close_projects())))
354 active_project(edit
, FALSE
);
359 case 202: /* Copy to clipboard */
360 if( edit
->ccp
.select
== 0 ) break;
362 if( CBWriteFTXT(edit
->ccp
.yc
> edit
->ccp
.yp
? edit
->ccp
.line
: edit
->ccp
.cline
, &edit
->ccp
) ) {
363 if( MenuID
== 202 ) unmark_all(edit
,TRUE
);
364 else del_block( edit
);
367 case 203: /* Paste from clipboard */
370 if( !CBReadCHRS(&edit
->undo
, edit
->edited
, edit
->nbc
, buf
) )
371 /* CBReadCHRS will show the right error */
374 /* Just one line concerned? */
375 edit
->max_lines
+= buf
[2];
376 if( buf
[1] == 0 ) REDRAW_CURLINE(edit
)
378 /* Move cursor to the end of pasted text? */
379 if( shift
== 0 ) move_cursor(edit
,buf
[0],buf
[1]);
380 if( buf
[1]>0 ) redraw_content(edit
,edit
->show
,gui
.topcurs
,gui
.nbline
);
381 if( edit
->ccp
.select
) move_selection(edit
, edit
->nbrc
, edit
->nbl
);
382 inv_curs(edit
,TRUE
); prop_adj(edit
);
384 case 204: /* Mark text */
385 if(shift
) MenuID
=205;
386 case 205: /* Mark columnar */
387 move_selection
= SwitchSelect(edit
,MenuID
-204,0);
389 case 206: mark_all(edit
); break; /* Select all */
390 case 207: amiga_k(edit
); break; /* Del line */
391 case 2071: indent_by(edit
,'\t', 1); break; /* Indent */
392 case 2072: indent_by(edit
,'\t',-1); break; /* Unindent */
393 case 2073: change_case(edit
,0); break; /* Upper */
394 case 2074: change_case(edit
,1); break; /* Lower */
395 case 2075: change_case(edit
,2); break; /* Toggle */
396 case 208: insert_file(edit
); break; /* Insert file */
399 rollback(&edit
->undo
); break; /* Undo */
401 case 210: rollback(&edit
->redo
); break; /* Redo */
402 case 301: setup_winsearch(edit
,0); break; /* Search */
403 case 302: setup_winsearch(edit
,1); break; /* Replace */
404 case 3031: FindPattern(edit
, 1); break; /* Find next */
405 case 3032: FindPattern(edit
,-1); break; /* Find prev */
406 case 3033: ReplacePattern(edit
); break; /* Replace next */
407 case 304: pg_updown(edit
,-1); break; /* PgUp */
408 case 305: pg_updown(edit
, 1); break; /* PgDown */
409 case 306: goto_line(edit
); break; /* Goto line */
410 case 307: match_bracket(edit
); break; /* Match bracket */
411 case 308: last_modif(&edit
->undo
,0); break; /* Last modif */
412 case 309: horiz_pos(edit
,0); break; /* Home */
413 case 310: horiz_pos(edit
,MAXPOS
); break; /* End */
414 case 401: start_macro(); break; /* Record */
415 case 402: stop_macro(); break; /* Stop recording */
417 if(shift
== 0) { play_macro(1); break; } /* Play current macro */
418 case 404: repeat_macro(edit
); break; /* Repeat one or more times */
419 case 501: ask_new_screen(); break; /* Change screen mode */
420 case 502: ask_new_font(); break; /* Change text font */
421 case 503: setup_winpref(); break; /* General prefs */
422 case 505: save_prefs(&prefs
); break; /* Save prefs */
424 case 504: ask_prefs(edit
,0,GetMenuText(504)); break; /* Load prefs */
425 case 506: ask_prefs(edit
,1,GetMenuText(506)); break; /* Save prefs as */
430 /** Public port of Jano **/
431 static struct MsgPort
*port
= NULL
, *reply
;
432 static struct JPacket
*cmd
= NULL
;
434 UBYTE
*PortName
= JANO_PORT
;
436 /** Look if jano is already running **/
437 char find_janoed( StartUpArgs
*args
)
440 if( (reply
= (struct MsgPort
*) FindPort(PortName
)) )
442 PortName
= NULL
; /* Private port */
443 if( ( sigwait
= create_port() ) )
445 /* Send to JanoEditor that someone tries to start it again */
446 cmd
->class = CMD_NEWEDIT
;
447 cmd
->msg
.args
= args
;
448 PutMsg(reply
, (struct Message
*)cmd
);
449 /* cmd packet is associated with "port", thus reply will be done here */
450 Wait( sigwait
| SIGBREAKF_CTRL_C
);
451 /* Unqueue message */
454 /* Cleanup will be done later */
459 /** Setup public port of the editor **/
460 ULONG
create_port( void )
462 /* Create a port and */
463 if( ( port
= (struct MsgPort
*) CreateMsgPort() ) )
465 /* Set this port public */
466 port
->mp_Node
.ln_Name
= PortName
;
467 port
->mp_Node
.ln_Pri
= 0;
470 /* Create a message that can be sent to the editor */
471 if( ( cmd
= (struct JPacket
*) CreateIORequest(port
, (long) sizeof (*cmd
)) ) )
472 return (ULONG
)(1 << port
->mp_SigBit
);
479 /** Send a command to preference tool **/
480 char send_pref(PREFS
*prefs
, ULONG
class)
482 /* The port can be shutted down at any time! */
483 if( ( reply
= (struct MsgPort
*) FindPort(JANOPREFS_PORT
)) )
486 CopyMem(prefs
, &cmd
->msg
.prefs
, sizeof(*prefs
));
488 PutMsg(reply
, (struct Message
*)cmd
);
489 Wait( 1 << port
->mp_SigBit
| SIGBREAKF_CTRL_C
);
495 /** Shutdown port **/
496 void close_port( void )
498 if( cmd
) DeleteExtIO((struct IORequest
*)cmd
);
499 if( port
) RemPort(port
), DeleteMsgPort(port
);
502 /*** Handle messages posted to public port of Jano ***/
503 void handle_port( void )
505 struct JPacket
*msg
; char update
= 0;
506 extern PREFS tmpprefs
;
507 while( ( msg
= (struct JPacket
*) GetMsg(port
) ) )
512 /* Look if there are projects to load */
513 if(msg
->msg
.args
->sa_NbArgs
> 0)
515 inv_curs(edit
, FALSE
);
516 edit
= create_projects(edit
, msg
->msg
.args
->sa_ArgLst
, msg
->msg
.args
->sa_NbArgs
);
518 active_project(edit
,TRUE
);
522 WindowToFront( Wnd
);
523 ScreenToFront( Scr
);
524 ActivateWindow( Wnd
);
526 case CMD_KILL
: cleanup(0,0); break;
528 /* Send a copy of preference struct */
530 CopyMem(&prefs
, &msg
->msg
.prefs
, sizeof(prefs
));
532 case CMD_SAVPREF
: update
= 2; goto save
;
533 case CMD_NEWPREF
: update
= 1;
534 /* Preference tool has sent a new config! */
535 save
: CopyMem(&msg
->msg
.prefs
, &tmpprefs
, sizeof(tmpprefs
)); break;
537 ReplyMsg((struct Message
*)msg
);
539 /* Preferences have changed? */
540 if(update
== 2) save_prefs(&tmpprefs
);
541 if(update
>= 1) update_prefs(edit
);