1 /* Copyright (C) 2000 Damir Zucic */
2
3 /*=============================================================================
4
5 key_press.c
6
7 Purpose:
8 Handle KeyPress events.
9
10 Input:
11 (1) Pointer to MolComplexS structure, with macromol. complexes.
12 (2) Number of macromolecular complexes.
13 (3) Pointer to the next macromolecular complex identifier.
14 (4) Pointer to RuntimeS structure, with some runtime data.
15 (5) Pointer to ConfigS structure, with configuration data.
16 (6) Pointer to GUIS structure, with GUI data.
17 (7) Pointer to pointer to NearestAtomS structure.
18 (8) Pointer to the number of pixels in the main window free area.
19 (9) Pointer to refreshI.
20 (10) Pointer to XKeyEvent structure.
21
22 Output:
23 (1) Some action performed.
24 (2) Return value.
25
26 Return value:
27 (1) Positive or zero on success. If positive value is returned,
28 it should be interpreted as command code returned by the
29 function ExecuteCommand1_ ().
30 (2) Negative, if ExecuteCommand1_ () function failes. The value
31 should be interpreted as (internal) error code.
32
33 Notes:
34 (1) The value of refreshI (*refreshIP) may be changed in this
35 function. It is checked in EventLoop_ (see event_loop.c).
36 It is assumed that refreshI is updated no more than once in
37 each event handling function. If this is not the case, the
38 care should be taken to avoid refreshI overflow.
39
40 ========includes:============================================================*/
41
42 #include <stdio.h>
43
44 #include <ctype.h>
45
46 #include <X11/Xlib.h>
47 #include <X11/Xutil.h>
48 #include <X11/Xos.h>
49 #include <X11/Xatom.h>
50
51 #include <X11/keysym.h>
52
53 #include "defines.h"
54 #include "typedefs.h"
55
56 /*======function prototypes:=================================================*/
57
58 double RotationAngle_ (ConfigS *, GUIS *, double);
59 int Rotate_ (MolComplexS *, int,
60 RuntimeS *, ConfigS *, double, int);
61 size_t MainRefresh_ (MolComplexS *, int,
62 RuntimeS *, ConfigS *, GUIS *,
63 NearestAtomS *, size_t, unsigned int);
64 int ControlRefresh_ (MolComplexS *, ConfigS *, GUIS *);
65 int DockingRefresh_ (RuntimeS *, GUIS *);
66 double TranslationShift_ (ConfigS *, GUIS *, double);
67 void Translate_ (MolComplexS *, int,
68 RuntimeS *, ConfigS *, double, int);
69 double SlabShift_ (ConfigS *, GUIS *, double);
70 void MoveBackSlab_ (MolComplexS *, int, ConfigS *, double);
71 void MoveFrontSlab_ (MolComplexS *, int, ConfigS *, double);
72 double FadingShift_ (ConfigS *, GUIS *, double);
73 void MoveBackFading_ (MolComplexS *, int, ConfigS *, double);
74 void MoveFrontFading_ (MolComplexS *, int, ConfigS *, double);
75 int AddCharToCommand_ (RuntimeS *, GUIS *, int);
76 int InputRefresh_ (GUIS *, RuntimeS *);
77 int EatLeftChar_ (RuntimeS *);
78 int EatRightChar_ (RuntimeS *);
79 int ExecuteCommand1_ (MolComplexS *, int *, int *,
80 RuntimeS *, ConfigS *, GUIS *,
81 NearestAtomS **, size_t *, unsigned int *);
82 int TruncateCommand_ (RuntimeS *);
83 int ReplaceCommand_ (RuntimeS *, int, GUIS *);
84 void InitNearest_ (NearestAtomS *, size_t);
85
86 /*======handle KeyPress events:==============================================*/
87
KeyPress_(MolComplexS * mol_complexSP,int * mol_complexesNP,int * next_mol_complexIDP,RuntimeS * runtimeSP,ConfigS * configSP,GUIS * guiSP,NearestAtomS ** nearest_atomSPP,size_t * pixelsNP,unsigned int * refreshIP,XKeyEvent * key_eventSP)88 int KeyPress_ (MolComplexS *mol_complexSP, int *mol_complexesNP,
89 int *next_mol_complexIDP,
90 RuntimeS *runtimeSP, ConfigS *configSP, GUIS *guiSP,
91 NearestAtomS **nearest_atomSPP, size_t *pixelsNP,
92 unsigned int *refreshIP,
93 XKeyEvent *key_eventSP)
94 {
95 static char stringA[STRINGSIZE];
96 static KeySym key_symID;
97 static XComposeStatus compose_statusS;
98 static double rotation_angle;
99 static double shift;
100 static int carriage_pos, comm_length;
101 static int new_char;
102 static int command_code;
103 static int n;
104
105 /* Get the KeySym: */
106 XLookupString (key_eventSP, stringA, STRINGSIZE, &key_symID, &compose_statusS);
107
108 /* Select the proper action for a given KeySym: */
109 switch (key_symID)
110 {
111
112 /*------modifiers:-----------------------------------------------------------*/
113
114 /* Shift key pressed: */
115 case XK_Shift_L:
116 case XK_Shift_R:
117 guiSP->shift_pressedF = 1;
118 break;
119
120 /* Control key pressed: */
121 case XK_Control_L:
122 case XK_Control_R:
123 guiSP->control_pressedF = 1;
124 break;
125
126 /* Alt or meta key pressed: */
127 case XK_Alt_L:
128 case XK_Alt_R:
129 case XK_Meta_L:
130 case XK_Meta_R:
131 guiSP->alt_pressedF = 1;
132 break;
133
134 /*------rotations:-----------------------------------------------------------*/
135
136 /* Right-handed (positive) rotation about x: */
137 case XK_KP_2:
138 case XK_KP_Down:
139 (*refreshIP)++;
140 rotation_angle = RotationAngle_ (configSP, guiSP, 1.0);
141 Rotate_ (mol_complexSP, *mol_complexesNP,
142 runtimeSP, configSP, rotation_angle, 1);
143 MainRefresh_ (mol_complexSP, *mol_complexesNP,
144 runtimeSP, configSP, guiSP,
145 *nearest_atomSPP, *pixelsNP, *refreshIP);
146 ControlRefresh_ (mol_complexSP + runtimeSP->default_complexI,
147 configSP, guiSP);
148 if (guiSP->dockingF) DockingRefresh_ (runtimeSP, guiSP);
149 break;
150
151
152 /* Left-handed (negative) rotation about x: */
153 case XK_KP_8:
154 case XK_KP_Up:
155 (*refreshIP)++;
156 rotation_angle = RotationAngle_ (configSP, guiSP, -1.0);
157 Rotate_ (mol_complexSP, *mol_complexesNP,
158 runtimeSP, configSP, rotation_angle, 1);
159 MainRefresh_ (mol_complexSP, *mol_complexesNP,
160 runtimeSP, configSP, guiSP,
161 *nearest_atomSPP, *pixelsNP, *refreshIP);
162 ControlRefresh_ (mol_complexSP + runtimeSP->default_complexI,
163 configSP, guiSP);
164 if (guiSP->dockingF) DockingRefresh_ (runtimeSP, guiSP);
165 break;
166
167 /* Right-handed (positive) rotation about y: */
168 case XK_KP_4:
169 case XK_KP_Left:
170 (*refreshIP)++;
171 rotation_angle = RotationAngle_ (configSP, guiSP, +1.0);
172 Rotate_ (mol_complexSP, *mol_complexesNP,
173 runtimeSP, configSP, rotation_angle, 2);
174 MainRefresh_ (mol_complexSP, *mol_complexesNP,
175 runtimeSP, configSP, guiSP,
176 *nearest_atomSPP, *pixelsNP, *refreshIP);
177 ControlRefresh_ (mol_complexSP + runtimeSP->default_complexI,
178 configSP, guiSP);
179 if (guiSP->dockingF) DockingRefresh_ (runtimeSP, guiSP);
180 break;
181
182 /* Left-handed (negative) rotation about y: */
183 case XK_KP_6:
184 case XK_KP_Right:
185 (*refreshIP)++;
186 rotation_angle = RotationAngle_ (configSP, guiSP, -1.0);
187 Rotate_ (mol_complexSP, *mol_complexesNP,
188 runtimeSP, configSP, rotation_angle, 2);
189 MainRefresh_ (mol_complexSP, *mol_complexesNP,
190 runtimeSP, configSP, guiSP,
191 *nearest_atomSPP, *pixelsNP, *refreshIP);
192 ControlRefresh_ (mol_complexSP + runtimeSP->default_complexI,
193 configSP, guiSP);
194 if (guiSP->dockingF) DockingRefresh_ (runtimeSP, guiSP);
195 break;
196
197 /* Right-handed (positive) rotation about z: */
198 case XK_KP_9:
199 case XK_KP_Prior:
200 (*refreshIP)++;
201 rotation_angle = RotationAngle_ (configSP, guiSP, +1.0);
202 Rotate_ (mol_complexSP, *mol_complexesNP,
203 runtimeSP, configSP, rotation_angle, 3);
204 MainRefresh_ (mol_complexSP, *mol_complexesNP,
205 runtimeSP, configSP, guiSP,
206 *nearest_atomSPP, *pixelsNP, *refreshIP);
207 ControlRefresh_ (mol_complexSP + runtimeSP->default_complexI,
208 configSP, guiSP);
209 if (guiSP->dockingF) DockingRefresh_ (runtimeSP, guiSP);
210 break;
211
212 /* Left-handed (negative) rotation about z: */
213 case XK_KP_7:
214 case XK_KP_Home:
215 (*refreshIP)++;
216 rotation_angle = RotationAngle_ (configSP, guiSP, -1.0);
217 Rotate_ (mol_complexSP, *mol_complexesNP,
218 runtimeSP, configSP, rotation_angle, 3);
219 MainRefresh_ (mol_complexSP, *mol_complexesNP,
220 runtimeSP, configSP, guiSP,
221 *nearest_atomSPP, *pixelsNP, *refreshIP);
222 ControlRefresh_ (mol_complexSP + runtimeSP->default_complexI,
223 configSP, guiSP);
224 if (guiSP->dockingF) DockingRefresh_ (runtimeSP, guiSP);
225 break;
226
227 /*------translations:--------------------------------------------------------*/
228
229 /* Positive translation along x: */
230 case XK_KP_Multiply:
231 case XK_KP_F4:
232 (*refreshIP)++;
233 shift = TranslationShift_ (configSP, guiSP, +1.0);
234 Translate_ (mol_complexSP, *mol_complexesNP,
235 runtimeSP, configSP, shift, 1);
236 MainRefresh_ (mol_complexSP, *mol_complexesNP,
237 runtimeSP, configSP, guiSP,
238 *nearest_atomSPP, *pixelsNP, *refreshIP);
239 if (guiSP->dockingF) DockingRefresh_ (runtimeSP, guiSP);
240 break;
241
242 /* Negative translation along x: */
243 case XK_KP_Divide:
244 case XK_KP_F3:
245 (*refreshIP)++;
246 shift = TranslationShift_ (configSP, guiSP, -1.0);
247 Translate_ (mol_complexSP, *mol_complexesNP,
248 runtimeSP, configSP, shift, 1);
249 MainRefresh_ (mol_complexSP, *mol_complexesNP,
250 runtimeSP, configSP, guiSP,
251 *nearest_atomSPP, *pixelsNP, *refreshIP);
252 if (guiSP->dockingF) DockingRefresh_ (runtimeSP, guiSP);
253 break;
254
255 /* Positive translation along y: */
256 case XK_KP_Add:
257 case XK_KP_Separator:
258 (*refreshIP)++;
259 shift = TranslationShift_ (configSP, guiSP, +1.0);
260 Translate_ (mol_complexSP, *mol_complexesNP,
261 runtimeSP, configSP, shift, 2);
262 MainRefresh_ (mol_complexSP, *mol_complexesNP,
263 runtimeSP, configSP, guiSP,
264 *nearest_atomSPP, *pixelsNP, *refreshIP);
265 if (guiSP->dockingF) DockingRefresh_ (runtimeSP, guiSP);
266 break;
267
268 /* Negative translation along y: */
269 case XK_KP_Subtract:
270 (*refreshIP)++;
271 shift = TranslationShift_ (configSP, guiSP, -1.0);
272 Translate_ (mol_complexSP, *mol_complexesNP,
273 runtimeSP, configSP, shift, 2);
274 MainRefresh_ (mol_complexSP, *mol_complexesNP,
275 runtimeSP, configSP, guiSP,
276 *nearest_atomSPP, *pixelsNP, *refreshIP);
277 if (guiSP->dockingF) DockingRefresh_ (runtimeSP, guiSP);
278 break;
279
280 /* Positive translation along z: */
281 case XK_KP_5:
282 case XK_KP_Begin:
283 (*refreshIP)++;
284 shift = TranslationShift_ (configSP, guiSP, +1.0);
285 Translate_ (mol_complexSP, *mol_complexesNP,
286 runtimeSP, configSP, shift, 3);
287 MainRefresh_ (mol_complexSP, *mol_complexesNP,
288 runtimeSP, configSP, guiSP,
289 *nearest_atomSPP, *pixelsNP, *refreshIP);
290 if (guiSP->dockingF) DockingRefresh_ (runtimeSP, guiSP);
291 break;
292
293 /* Negative translation along z: */
294 case XK_KP_0:
295 case XK_KP_Insert:
296 (*refreshIP)++;
297 shift = TranslationShift_ (configSP, guiSP, -1.0);
298 Translate_ (mol_complexSP, *mol_complexesNP,
299 runtimeSP, configSP, shift, 3);
300 MainRefresh_ (mol_complexSP, *mol_complexesNP,
301 runtimeSP, configSP, guiSP,
302 *nearest_atomSPP, *pixelsNP, *refreshIP);
303 if (guiSP->dockingF) DockingRefresh_ (runtimeSP, guiSP);
304 break;
305
306 /*------slab:----------------------------------------------------------------*/
307
308 /* Push the back slab surface farther: */
309 case XK_KP_1:
310 case XK_KP_End:
311 (*refreshIP)++;
312 shift = SlabShift_ (configSP, guiSP, 1.0);
313 MoveBackSlab_ (mol_complexSP, *mol_complexesNP,
314 configSP, shift);
315 MainRefresh_ (mol_complexSP, *mol_complexesNP,
316 runtimeSP, configSP, guiSP,
317 *nearest_atomSPP, *pixelsNP, *refreshIP);
318 ControlRefresh_ (mol_complexSP + runtimeSP->default_complexI,
319 configSP, guiSP);
320 break;
321
322 /* Pull the back slab surface closer: */
323 case XK_KP_3:
324 case XK_KP_Next:
325 (*refreshIP)++;
326 shift = SlabShift_ (configSP, guiSP, -1.0);
327 MoveBackSlab_ (mol_complexSP, *mol_complexesNP,
328 configSP, shift);
329 MainRefresh_ (mol_complexSP, *mol_complexesNP,
330 runtimeSP, configSP, guiSP,
331 *nearest_atomSPP, *pixelsNP, *refreshIP);
332 ControlRefresh_ (mol_complexSP + runtimeSP->default_complexI,
333 configSP, guiSP);
334 break;
335
336 /* Push the front slab surface farther: */
337 case XK_KP_Delete:
338 case XK_KP_Decimal:
339 (*refreshIP)++;
340 shift = SlabShift_ (configSP, guiSP, 1.0);
341 MoveFrontSlab_ (mol_complexSP, *mol_complexesNP,
342 configSP, shift);
343 MainRefresh_ (mol_complexSP, *mol_complexesNP,
344 runtimeSP, configSP, guiSP,
345 *nearest_atomSPP, *pixelsNP, *refreshIP);
346 ControlRefresh_ (mol_complexSP + runtimeSP->default_complexI,
347 configSP, guiSP);
348 break;
349
350 /* Pull the front slab surface closer: */
351 case XK_KP_Enter:
352 (*refreshIP)++;
353 shift = SlabShift_ (configSP, guiSP, -1.0);
354 MoveFrontSlab_ (mol_complexSP, *mol_complexesNP,
355 configSP, shift);
356 MainRefresh_ (mol_complexSP, *mol_complexesNP,
357 runtimeSP, configSP, guiSP,
358 *nearest_atomSPP, *pixelsNP, *refreshIP);
359 ControlRefresh_ (mol_complexSP + runtimeSP->default_complexI,
360 configSP, guiSP);
361 break;
362
363 /*------fading:--------------------------------------------------------------*/
364
365 /* Push the back fading surface farther: */
366 case XK_F1:
367 (*refreshIP)++;
368 shift = FadingShift_ (configSP, guiSP, 1.0);
369 MoveBackFading_ (mol_complexSP, *mol_complexesNP,
370 configSP, shift);
371 MainRefresh_ (mol_complexSP, *mol_complexesNP,
372 runtimeSP, configSP, guiSP,
373 *nearest_atomSPP, *pixelsNP, *refreshIP);
374 ControlRefresh_ (mol_complexSP + runtimeSP->default_complexI,
375 configSP, guiSP);
376 break;
377
378 /* Pull the back fading surface closer: */
379 case XK_F2:
380 (*refreshIP)++;
381 shift = FadingShift_ (configSP, guiSP, -1.0);
382 MoveBackFading_ (mol_complexSP, *mol_complexesNP,
383 configSP, shift);
384 MainRefresh_ (mol_complexSP, *mol_complexesNP,
385 runtimeSP, configSP, guiSP,
386 *nearest_atomSPP, *pixelsNP, *refreshIP);
387 ControlRefresh_ (mol_complexSP + runtimeSP->default_complexI,
388 configSP, guiSP);
389 break;
390
391 /* Push the front fading surface farther: */
392 case XK_F3:
393 (*refreshIP)++;
394 shift = FadingShift_ (configSP, guiSP, 1.0);
395 MoveFrontFading_ (mol_complexSP, *mol_complexesNP,
396 configSP, shift);
397 MainRefresh_ (mol_complexSP, *mol_complexesNP,
398 runtimeSP, configSP, guiSP,
399 *nearest_atomSPP, *pixelsNP, *refreshIP);
400 ControlRefresh_ (mol_complexSP + runtimeSP->default_complexI,
401 configSP, guiSP);
402 break;
403
404 /* Pull the front fading surface closer: */
405 case XK_F4:
406 (*refreshIP)++;
407 shift = FadingShift_ (configSP, guiSP, -1.0);
408 MoveFrontFading_ (mol_complexSP, *mol_complexesNP,
409 configSP, shift);
410 MainRefresh_ (mol_complexSP, *mol_complexesNP,
411 runtimeSP, configSP, guiSP,
412 *nearest_atomSPP, *pixelsNP, *refreshIP);
413 ControlRefresh_ (mol_complexSP + runtimeSP->default_complexI,
414 configSP, guiSP);
415 break;
416
417 /*------line editing:--------------------------------------------------------*/
418
419 /* Move the input window carriage (keyboard cursor) to the left: */
420 case XK_Left:
421 carriage_pos = runtimeSP->carriage_position;
422 carriage_pos--;
423 if (carriage_pos >= 0)
424 {
425 runtimeSP->carriage_position = carriage_pos;
426 InputRefresh_ (guiSP, runtimeSP);
427 }
428 break;
429
430 /* Move the input window carriage (keyboard cursor) to the right: */
431 case XK_Right:
432 carriage_pos = runtimeSP->carriage_position;
433 comm_length = runtimeSP->command_length;
434 carriage_pos++;
435 if (carriage_pos <= comm_length)
436 {
437 runtimeSP->carriage_position = carriage_pos;
438 InputRefresh_ (guiSP, runtimeSP);
439 }
440 break;
441
442 /* Replace the current command with the previous one, if available: */
443 case XK_Up:
444 n = ReplaceCommand_ (runtimeSP, -1, guiSP);
445 if (n < 0) break;
446 InputRefresh_ (guiSP, runtimeSP);
447 break;
448
449 /* Replace the current command with the next one (if available): */
450 case XK_Down:
451 n = ReplaceCommand_ (runtimeSP, +1, guiSP);
452 if (n < 0) break;
453 InputRefresh_ (guiSP, runtimeSP);
454 break;
455
456 /* Move the input window carriage to the beginning of command line: */
457 case XK_Home:
458 runtimeSP->carriage_position = 0;
459 InputRefresh_ (guiSP, runtimeSP);
460 break;
461
462 /* Move the input window carrriage to the end of command line: */
463 case XK_End:
464 runtimeSP->carriage_position = runtimeSP->command_length;
465 InputRefresh_ (guiSP, runtimeSP);
466 break;
467
468 /* Remove one character on the left side: */
469 case XK_BackSpace:
470 EatLeftChar_ (runtimeSP);
471 InputRefresh_ (guiSP, runtimeSP);
472 break;
473
474 /* Remove one character on the right side: */
475 case XK_Delete:
476 EatRightChar_ (runtimeSP);
477 InputRefresh_ (guiSP, runtimeSP);
478 break;
479
480 /*------command execution:---------------------------------------------------*/
481
482 /* Print command string to log file (if requested), */
483 /* execute command, truncate command string, reset */
484 /* the string length and refresh the input window. */
485 /* If some kind of error occurs, the return code */
486 /* should be negative. In that case, print the */
487 /* error message to log file (if it is requested). */
488 case XK_Return:
489 /** Print command to log file, if requested: **/
490 if (configSP->log_fileF)
491 {
492 fprintf (configSP->log_fileP, "%s\n",
493 runtimeSP->curr_commandA);
494 fflush (configSP->log_fileP);
495 }
496
497 /** Parse command string and execute command: **/
498 command_code = ExecuteCommand1_ (
499 mol_complexSP, mol_complexesNP,
500 next_mol_complexIDP,
501 runtimeSP, configSP, guiSP,
502 nearest_atomSPP, pixelsNP, refreshIP);
503
504 /** Print the latest message to log file, if requested: **/
505 if ((command_code < 0) && (configSP->log_fileF))
506 {
507 fprintf (configSP->log_fileP, "#%s\n",
508 runtimeSP->messageA);
509 fflush (configSP->log_fileP);
510 }
511
512 /** Truncate the command string: **/
513 TruncateCommand_ (runtimeSP);
514
515 /** Refresh (redraw) the input window: **/
516 InputRefresh_ (guiSP, runtimeSP);
517
518 /** Update and check the command index **/
519 /** and the total number of commands: **/
520 runtimeSP->next_commandI++;
521 if (runtimeSP->next_commandI >= MAXCOMMSTRINGS - 1)
522 {
523 runtimeSP->next_commandI = 0;
524 }
525 if (runtimeSP->highest_commandI < MAXCOMMSTRINGS - 1)
526 {
527 runtimeSP->highest_commandI++;
528 }
529
530 /** Update the old_commandI: **/
531 runtimeSP->old_commandI = runtimeSP->next_commandI;
532
533 /** Return command code to the caller: **/
534 return command_code;
535 break;
536
537 /*------escape key causes return to the main drawing mode:-------------------*/
538
539 /* Reset main window drawing mode and refresh the main window: */
540 case XK_Escape:
541 /* Reset drawing mode index: */
542 guiSP->main_window_modeI = 0;
543
544 /* Reinitialize the NearestAtomS array: */
545 InitNearest_ (*nearest_atomSPP, *pixelsNP);
546 *refreshIP = 1;
547
548 /* Refresh the main window: */
549 (*refreshIP)++;
550 MainRefresh_ (mol_complexSP, *mol_complexesNP,
551 runtimeSP, configSP, guiSP,
552 *nearest_atomSPP, *pixelsNP, *refreshIP);
553
554 /* Refresh the control window: */
555 ControlRefresh_ (mol_complexSP + runtimeSP->default_complexI,
556 configSP, guiSP);
557 break;
558
559 /*------character input:-----------------------------------------------------*/
560
561 /* All other keys should belong to the current command string: */
562 default:
563 /** Check the character: **/
564 new_char = stringA[0];
565 if (!isprint (new_char)) break;
566
567 /** Append the character to the command string: **/
568 if (AddCharToCommand_ (runtimeSP, guiSP, new_char) < 0) break;
569
570 /** Refresh the input window: **/
571 InputRefresh_ (guiSP, runtimeSP);
572 ;
573
574 /*---------------------------------------------------------------------------*/
575
576 }
577
578 /* Return zero if this point is reached: */
579 return 0;
580 }
581
582 /*===========================================================================*/
583
584
585