Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
BitchX
GitHub Repository: BitchX/BitchX1.3
Path: blob/master/source/keys.c
1069 views
1
/*
2
* keys.c: Keeps track of what happens whe you press a key.
3
*
4
* Written By Michael Sandrof
5
* Copyright(c) 1990 Michael Sandrof
6
* See the COPYRIGHT file, or do a HELP IRCII COPYRIGHT
7
*
8
* Substantial re-implementation by Jeremy Nelson
9
* Copyright 1998 EPIC Software Labs
10
* See the COPYRIGHT file, or do a HELP IRCII COPYRIGHT
11
*/
12
13
#include "irc.h"
14
static char cvsrevision[] = "$Id: keys.c 3 2008-02-25 09:49:14Z keaston $";
15
CVS_REVISION(keys_c)
16
#include "struct.h"
17
#include "config.h"
18
#include "commands.h"
19
#include "history.h"
20
#include "ircaux.h"
21
#include "input.h"
22
#include "keys.h"
23
#include "names.h"
24
#include "output.h"
25
#include "screen.h"
26
#include "ircterm.h"
27
#include "vars.h"
28
#include "window.h"
29
#define MAIN_SOURCE
30
#include "modval.h"
31
32
#define KEY(meta, ch) (*keys[meta])[ch]
33
34
typedef unsigned char uc;
35
static void new_key (int, unsigned, int, int, char *);
36
static void snew_key (int meta, unsigned chr, char *what);
37
static uc * display_key (uc c);
38
static int lookup_function (const uc *name, int *lf_index);
39
static int parse_key (const uc *sequence, uc *term);
40
41
#ifdef GUI
42
char *mouse_actions[] =
43
{
44
"RCLICK",
45
"STATUSRCLICK",
46
"NICKLISTRCLICK",
47
"LCLICK",
48
"STATUSLCLICK",
49
"NICKLISTLCLICK",
50
"MCLICK",
51
"STATUSMCLICK",
52
"NICKLISTMCLICK",
53
"RDBLCLICK",
54
"STATUSRDBLCLICK",
55
"NICKLISTRDBLCLICK",
56
"LDBLCLICK",
57
"STATUSLDBLCLICK",
58
"NICKLISTLDBLCLICK",
59
"MDBLCLICK",
60
"STATUSMDBLCLICK",
61
"NICKLISTMDBLCLICK"
62
};
63
#endif
64
65
66
67
/*
68
* Yet again we've changed how the key maps are held. This time, hopefully
69
* its the second to last time, as we've made the entire things independant
70
* of the number of meta keymaps that are available (it can change.) The
71
* only thing i see left to be done is to encapsulate all this data inside
72
* a class so that different contexts can have different bindings sets.
73
* I'm sure that will come up some day. But anyhow, on to the details!
74
*/
75
76
/*
77
* The actual "stuff" that is in a keybinding is defined in keys.h.
78
* At the time i write this, its just an int, two pointers, and a char,
79
* so its 16 bytes (after padding)....
80
*
81
* typedef struct
82
* {
83
* int key_index;
84
* char *stuff;
85
* char *filename;
86
* char changed;
87
* } KeyMap;
88
*
89
* Some special notes about 'key_index'. No longer are the meta bindings
90
* just normal bindings -- having them hardcoded as normal bindings limited
91
* the ability of the user to set the number of meta states that they wanted.
92
* Now all the negative values for 'key_index' are reserved for those meta
93
* states. If something is bound to META2_CHARACTER, then 'key_index' is
94
* given the value -2. Otherwise, 'key_index' is given the value of the
95
* entry of the binding in the 'key_names' table. Note that 'key_index' is
96
* not strictly sorted. The first two bindings are special and are hardcoded,
97
* and you must not change them. Entry 0 must always be "NOTHING", and
98
* entry 1 must always be "SELF_INSERT". The enum that was in keys.h
99
* is now totaly obsolete -- we no longer use the symbolic names, but instead
100
* always use the full string name for the binding. This makes it much
101
* easier to add new key bindings, as there is only one place to manage.
102
*
103
*
104
* Each meta map is a collection of 256 bindings...
105
*
106
* typedef KeyMap MetaMap[256];
107
*
108
* But since most of the meta maps are either sparse or empty, it makes very
109
* little sense to actually allocate 4k (16 * 256) for each of the maps only
110
* to have them unused. So instead the meta map is just 256 pointers to
111
* these objects, which then are allocated dynamically.
112
*
113
* typedef KeyMap *MetaMap[256]; (better)
114
*
115
* That means that the overhead for a completely empty meta map is 1k, and
116
* the map needs to be 75% full before it uses more memory than it would have
117
* otherwise. So its a reasonable win.
118
*
119
* Now we need to have the meta maps stored somehow. Originally, we used
120
* to just make an array of them...
121
*
122
* typedef MetaMap KeyTable[MAX_META];
123
*
124
* but then again, many of those MetaMaps are going to be totaly empty.
125
* Why should we allocate 1k to something that isnt going to be used?
126
* So instead we should keep pointers to the maps and allocate them as
127
* neccesary at runtime...
128
*
129
* typedef MetaMap *KeyTable[MAX_META]; (better)
130
*
131
* Which is what we had before. This works out fine, except, that the
132
* number of meta maps is hardcoded into the client at compile time.
133
* Wouldn't it be nice to be able to determine at runtime how many maps
134
* we want and be able to change them as neccesary? We can do this by
135
* having a pointer to the set of pointers of MetaMaps...
136
*
137
* typedef MetaMap **KeyTable; (dyanmic now)
138
*
139
* And so we dynamically allocate to MetaSet enough pointers to hold the
140
* number of MetaMap's we want. Then any time we want to use a MetaMap,
141
* we allocate space for it. Then any time we want to use a binding in the
142
* MetaMap, we allocate space for it and set its pointer.
143
*
144
* So the final dereference for a specific key binding 'X' in meta map 'Y' is:
145
*
146
* KeyTable keys;
147
* keys[Y] The pointer to the 'Y'th MetaMap
148
* (*keys[Y]) The MetaMap itself
149
* (*keys[Y])[X] The pointer to the 'X'th character in the
150
* 'Y'th MetaMap
151
* (*keys[Y])[X]->key_index
152
* What 'Y,X' is actually bound to. This is a
153
* negative value for a transition to a new
154
* meta state Y, positive for a terminating
155
* binding.
156
*/
157
158
/* * * * * * * * * * * * * * * METAMAP MANAGEMENT * * * * * * * * * * * */
159
/*
160
* This is where all the bindings are stored
161
* Also we store how big it thinks it is, and how big it actually is.
162
*/
163
164
/* KeyMapNames: the structure of the keymap to realname array */
165
typedef struct
166
{
167
char * name;
168
KeyBinding func;
169
} KeyMapNames;
170
static KeyMapNames key_names[] =
171
{
172
/* The first two here are "magic" binds */
173
{ "NOTHING", NULL },
174
{ "SELF_INSERT", input_add_character },
175
{ "ALTCHARSET", insert_altcharset },
176
{ "AUTOREPLY", input_autoreply },
177
{ "AUTOREPLY_BACK", input_autoreplyback },
178
{ "BACKSPACE", input_backspace },
179
{ "BACKWARD_CHARACTER", backward_character },
180
{ "BACKWARD_HISTORY", backward_history },
181
{ "BACKWARD_WORD", input_backward_word },
182
{ "BEGINNING_OF_LINE", input_beginning_of_line },
183
{ "BLINK", insert_blink },
184
{ "BOLD", insert_bold },
185
#ifdef WANT_CDCC
186
{ "CDCC_PLIST", cdcc_plist },
187
#endif
188
{ "CHANNEL_CHOPS", channel_chops },
189
{ "CHANNEL_NONOPS", channel_nonops },
190
{ "CHANGE_TO_SPLIT", change_to_split },
191
#ifdef WANT_CHELP
192
{ "CHELP", do_chelp },
193
#endif
194
{ "CLEAR_SCREEN", clear_screen },
195
{ "COMMAND_COMPLETION", command_completion },
196
{ "CPU_SAVER", cpu_saver_on },
197
{ "DCC_PLIST", dcc_plist },
198
{ "DCC_STATS", dcc_ostats },
199
{ "DELETE_CHARACTER", input_delete_character },
200
{ "DELETE_NEXT_WORD", input_delete_next_word },
201
{ "DELETE_PREVIOUS_WORD", input_delete_previous_word },
202
{ "DELETE_TO_PREVIOUS_SPACE", input_delete_to_previous_space },
203
{ "END_OF_LINE", input_end_of_line },
204
#ifdef TRANSLATE
205
{ "ENTER_DIGRAPH", enter_digraph },
206
#endif
207
{ "ERASE_LINE", input_clear_line },
208
{ "ERASE_TO_BEG_OF_LINE", input_clear_to_bol },
209
{ "ERASE_TO_END_OF_LINE", input_clear_to_eol },
210
{ "FORWARD_CHARACTER", forward_character },
211
{ "FORWARD_HISTORY", forward_history },
212
{ "FORWARD_WORD", input_forward_word },
213
{ "HIGHLIGHT_OFF", highlight_off },
214
{ "IGNORE_NICK", ignore_last_nick },
215
{ "JOIN_LAST_INVITE", join_last_invite },
216
{ "NEW_BEGINNING_OF_LINE", new_input_beginning_of_line },
217
{ "NEW_SCROLL_BACKWARD", my_scrollback },
218
{ "NEW_SCROLL_END", my_scrollend },
219
{ "NEW_SCROLL_FORWARD", my_scrollforward},
220
{ "NEXT_WINDOW", BX_next_window },
221
{ "NICK_COMPLETION", nick_completion },
222
{ "PARSE_COMMAND", parse_text },
223
#ifdef GUI
224
{ "PASTE_TO_INPUT", paste_to_input },
225
#endif
226
{ "PREVIOUS_WINDOW", BX_previous_window },
227
{ "QUIT_IRC", irc_quit },
228
{ "QUOTE_CHARACTER", quote_char },
229
{ "REFRESH_INPUTLINE", refresh_inputline },
230
{ "REFRESH_SCREEN", (KeyBinding) refresh_screen },
231
{ "REFRESH_STATUS", (KeyBinding) BX_update_all_status },
232
{ "REVERSE", insert_reverse },
233
{ "SCROLL_BACKWARD", BX_scrollback_backwards },
234
{ "SCROLL_END", BX_scrollback_end },
235
{ "SCROLL_FORWARD", BX_scrollback_forwards },
236
{ "SCROLL_START", BX_scrollback_start },
237
{ "SEND_LINE", send_line },
238
{ "SHOVE_TO_HISTORY", shove_to_history },
239
#ifdef ALLOW_STOP_IRC
240
{ "STOP_IRC", term_pause },
241
#endif
242
{ "SWAP_LAST_WINDOW", BX_swap_last_window },
243
{ "SWAP_NEXT_WINDOW", BX_swap_next_window },
244
{ "SWAP_PREVIOUS_WINDOW", BX_swap_previous_window },
245
{ "SWITCH_CHANNELS", switch_channels },
246
#ifdef WANT_TABKEY
247
{ "TAB_COMPLETION", tab_completion },
248
#endif
249
{ "TAB_MSG", input_msgreply },
250
{ "TAB_MSG_BACK", input_msgreplyback },
251
{ "TOGGLE_CLOAK", toggle_cloak },
252
{ "TOGGLE_INSERT_MODE", toggle_insert_mode },
253
{ "TOGGLE_STOP_SCREEN", BX_toggle_stop_screen },
254
{ "TRANSPOSE_CHARACTERS", input_transpose_characters },
255
{ "TYPE_TEXT", type_text },
256
{ "UNCLEAR_SCREEN", input_unclear_screen },
257
{ "UNDERLINE", insert_underline },
258
{ "UNSTOP_ALL_WINDOWS", BX_unstop_all_windows },
259
{ "WHOLEFT", wholeft },
260
{ "WINDOW_BALANCE", window_key_balance },
261
{ "WINDOW_GROW_ONE", window_grow_one },
262
#ifdef WANT_CHELP
263
{ "WINDOW_HELP", w_help },
264
#endif
265
{ "WINDOW_HIDE", window_key_hide },
266
{ "WINDOW_KILL", window_key_kill },
267
{ "WINDOW_LIST", window_key_list },
268
{ "WINDOW_MOVE", window_key_move },
269
{ "WINDOW_SHRINK_ONE", window_shrink_one },
270
271
{ "WINDOW_SWAP_1", window_swap1 },
272
{ "WINDOW_SWAP_2", window_swap2 },
273
{ "WINDOW_SWAP_3", window_swap3 },
274
{ "WINDOW_SWAP_4", window_swap4 },
275
{ "WINDOW_SWAP_5", window_swap5 },
276
{ "WINDOW_SWAP_6", window_swap6 },
277
{ "WINDOW_SWAP_7", window_swap7 },
278
{ "WINDOW_SWAP_8", window_swap8 },
279
{ "WINDOW_SWAP_9", window_swap9 },
280
{ "WINDOW_SWAP_10", window_swap10 },
281
{ "YANK_FROM_CUTBUFFER", input_yank_cut_buffer },
282
{ "NULL", NULL }
283
};
284
#define NUMBER_OF_FUNCTIONS (sizeof(key_names) / sizeof(KeyMapNames)) - 1
285
286
/* KeyMap: the structure of the irc keymaps */
287
typedef struct
288
{
289
int key_index;
290
char * stuff;
291
char * filename;
292
char changed;
293
} KeyMap;
294
typedef KeyMap * MetaMap[256];
295
typedef MetaMap ** KeyTable;
296
static KeyTable keys = NULL;
297
int curr_keys_size = 0;
298
static int max_keys_size = 0;
299
#define MAX_META curr_keys_size - 1
300
301
static void delete_metamap (int i);
302
303
/*
304
* resize_metamap -- When we need to increase or decrease the number of
305
* metamaps that the system is handling, you call this function with the
306
* new size, and everything automagically adjusts from there. This function
307
* always succeeds if it returns. This function is the callback for the
308
* /SET META_STATES action.
309
*/
310
void resize_metamap (int new_size)
311
{
312
int old_size = curr_keys_size;
313
int i, j;
314
315
/*
316
* Sorry, just too much will break if you go lower than 5.
317
*/
318
if (new_size < 5)
319
{
320
say("You can't set META_STATES to less than 5.");
321
set_int_var(META_STATES_VAR, 5);
322
}
323
324
if (old_size == new_size)
325
return; /* What-EVER */
326
327
/*
328
* If we're growing the meta table, resize and copy the data.
329
*/
330
if (old_size < new_size)
331
{
332
/*
333
* Realloc and copy if neccesary
334
*/
335
if (new_size > max_keys_size)
336
{
337
KeyTable new_keys;
338
new_keys = new_malloc(sizeof(KeyTable *) * new_size);
339
340
for (i = 0; i < old_size; i++)
341
new_keys[i] = keys[i];
342
for (i = old_size; i < new_size; i++)
343
new_keys[i] = NULL;
344
new_free((void **)&keys);
345
keys = new_keys;
346
max_keys_size = new_size;
347
}
348
curr_keys_size = new_size;
349
}
350
351
/*
352
* If we're shrinking the meta table, just garbage collect all
353
* the old bindings, dont actually bother resizing the table.
354
*/
355
else
356
{
357
for (i = new_size; i < old_size; i++)
358
delete_metamap(i);
359
curr_keys_size = new_size;
360
361
/*
362
* This is a bit tricky -- There might be meta transitions
363
* in other states that point to the now defunct states.
364
* If we leave those bindings around, then they will point
365
* to either meaningless, or bogus data, and either cause
366
* undefined behavior or a total program crash. So we walk
367
* all of the remaining states and garbage collect any
368
* meta transisions that are out of bounds.
369
*/
370
for (i = 0; i < new_size; i++)
371
{
372
if (!keys[i])
373
continue;
374
for (j = 0; j < 256; j++)
375
if (KEY(i, j) && (KEY(i, j)->key_index <= -new_size))
376
snew_key(i, j, NULL);
377
}
378
}
379
380
set_int_var(META_STATES_VAR, curr_keys_size);
381
}
382
383
384
/*
385
* new_metamap -- When you "touch" a metamap for the first time,
386
* the table for the 256 bindings in that metamap must be created, so
387
* you call this function to do that. You must never call this function
388
* unless the metamap does not exist, or it will panic.
389
*/
390
static void new_metamap (int which)
391
{
392
int j;
393
394
if (keys[which])
395
ircpanic("metamap already exists");
396
397
keys[which] = new_malloc(sizeof(MetaMap));
398
399
for (j = 0; j <= 255; j++)
400
KEY(which, j) = NULL;
401
}
402
403
/*
404
* delete_metamap -- When you're all done with a metamap you can call
405
* this function to garbage collect it. If there are any bindings in the
406
* metamap when you call this, they will be summarily disposed of.
407
*/
408
static void delete_metamap (int i)
409
{
410
int j;
411
412
/* This is cheating, but do i care? ;-) */
413
for (j = 0; j <= 255; j++)
414
snew_key(i, j, NULL);
415
416
new_free((char **)&keys[i]);
417
}
418
419
420
421
422
/* * * * * * * * * * * * * KEY BINDING MANAGEMENT * * * * * * * * * * * * */
423
/* special interface to new_key for the default key bindings */
424
static void snew_key (int meta, unsigned chr, char *what)
425
{
426
int i;
427
int j;
428
429
if ((j = lookup_function(what, &i)) == 1)
430
new_key(meta, chr, i, 0, NULL);
431
#if 0
432
else
433
ircpanic("Something bogus passed to snew_key");
434
#endif
435
}
436
437
static void snew_key_from_str (uc *string, char *what)
438
{
439
int i;
440
int meta;
441
int old_display;
442
uc chr;
443
444
old_display = window_display;
445
window_display = 0;
446
if ((meta = parse_key(string, &chr)) == -1)
447
return;
448
window_display = old_display;
449
450
if (lookup_function(what, &i) == 1)
451
new_key(meta, chr, i, 0, NULL);
452
453
return;
454
}
455
456
457
static void new_key (int meta, unsigned chr, int type, int change, char *stuff)
458
{
459
/*
460
* Create a map first time we bind into it. We have to do this
461
* Because its possible to do /bind METAX-f when there is not
462
* otherwise any key bound to METAX.
463
*/
464
if (!keys)
465
return;
466
if (!keys[meta])
467
new_metamap(meta);
468
469
if (KEY(meta, chr))
470
{
471
if (KEY(meta, chr)->stuff)
472
new_free(&(KEY(meta, chr)->stuff));
473
if (KEY(meta, chr)->filename)
474
new_free(&(KEY(meta, chr)->filename));
475
new_free(&(KEY(meta, chr)));
476
KEY(meta, chr) = NULL;
477
}
478
479
if (type != 0)
480
{
481
KEY(meta, chr) = (KeyMap *)new_malloc(sizeof(KeyMap));
482
KEY(meta, chr)->key_index = type;
483
KEY(meta, chr)->changed = change;
484
/* KEY(meta, chr)->filename = m_strdup(current_package());*/
485
if (stuff)
486
KEY(meta, chr)->stuff = m_strdup(stuff);
487
else
488
KEY(meta, chr)->stuff = NULL;
489
}
490
}
491
492
/*
493
* show_binding: Given an unsigned character 'X' in the meta map 'Y', this
494
* function will display to the screen the status of that bindings in a
495
* human-readable way.
496
*/
497
static void show_binding (int meta, uc c)
498
{
499
char meta_str[8];
500
501
*meta_str = 0;
502
if (meta < 1 || meta > MAX_META)
503
meta = 0;
504
else
505
sprintf(meta_str, "META%d-", meta);
506
507
if (keys[meta] && KEY(meta, c))
508
{
509
#ifdef GUI
510
if(meta == MAX_META && c < MAX_MOUSE)
511
say("%s is bound to %s %s", mouse_actions[c],
512
key_names[(*keys[meta])[c]->key_index].name,
513
SAFE(KEY(meta, c)->stuff));
514
else if (KEY(meta, c)->key_index < 0)
515
#else
516
if (KEY(meta, c)->key_index < 0)
517
#endif
518
say("%s%s is bound to META%d_CHARACTER",
519
meta_str,
520
display_key(c),
521
-(KEY(meta, c)->key_index));
522
else
523
say("%s%s is bound to %s %s",
524
meta_str,
525
display_key(c),
526
key_names[KEY(meta, c)->key_index].name,
527
SAFE(KEY(meta, c)->stuff));
528
}
529
else
530
say("%s%s is bound to NOTHING", meta_str, display_key(c));
531
}
532
533
#ifdef GUI
534
void wm_process(int param)
535
{
536
void (*func) (char, char *) = NULL;
537
char *ptr = NULL;
538
539
if (keys[MAX_META] && (*keys[MAX_META]) && (*keys[MAX_META])[param])
540
{
541
func = key_names[(*keys[MAX_META])[param]->key_index].func;
542
ptr = (*keys[MAX_META])[param]->stuff;
543
}
544
if (func)
545
func(param, ptr ? ptr : empty_string);
546
}
547
#endif
548
549
/*
550
* save_bindings: This writes all the key bindings for ircII to the given
551
* FILE pointer suitable for being /LOADed again in the future.
552
*/
553
void save_bindings (FILE *fp, int do_all)
554
{
555
int meta, j;
556
int charsize = charset_size();
557
char meta_str[10];
558
559
*meta_str = 0;
560
for (meta = 0; meta <= MAX_META; meta++)
561
{
562
if (meta != 0)
563
sprintf(meta_str, "META%d-", meta);
564
565
for (j = 0; j < charsize; j++)
566
{
567
if (keys[meta] && KEY(meta, j) && KEY(meta, j)->changed)
568
{
569
if (KEY(meta, j)->key_index < 0)
570
fprintf(fp, "BIND %s%s META%d\n",
571
meta_str,
572
display_key(j),
573
-(KEY(meta, j)->key_index));
574
else
575
fprintf(fp, "BIND %s%s %s %s\n",
576
meta_str,
577
display_key(j),
578
key_names[KEY(meta, j)->key_index].name,
579
SAFE(KEY(meta, j)->stuff));
580
}
581
}
582
}
583
}
584
585
/*
586
* This is a function used by edit_char to retreive the details for a
587
* specific key binding. This function provides the only external access
588
* to the key bindings. The arguments are the meta state and the character
589
* whose information you want to retreive. That information is stored into
590
* the 'func' and 'name' pointers you pass in.
591
*
592
* The function will return 0 if the binding you request is a "normal" one.
593
* If the binding is "NOTHING", then func will be set to NULL
594
* If the binding is an action, the func will be set to its callback.
595
*
596
* The function will return a positive number if the binding you request is
597
* a "meta" character.
598
* The value of 'func' will be NULL but you should not depend on that.
599
*/
600
int get_binding (int meta, uc c, KeyBinding *func, char **name)
601
{
602
*func = NULL;
603
*name = NULL;
604
605
if (meta >= 0 && meta <= MAX_META)
606
{
607
if (keys[meta] && KEY(meta, c))
608
{
609
/*
610
* If this is a meta binding, return the new meta
611
* state -- this is a "special" value.
612
*/
613
if (KEY(meta, c)->key_index < 0)
614
return -(KEY(meta, c)->key_index);
615
616
/*
617
* Otherwise, assign to 'func' and 'name' the
618
* appropriate values.
619
*/
620
*func = key_names[KEY(meta, c)->key_index].func;
621
*name = KEY(meta, c)->stuff;
622
}
623
}
624
return 0;
625
}
626
627
628
void remove_bindings (void)
629
{
630
int i;
631
632
for (i = 0; i <= MAX_META; i++)
633
delete_metamap(i);
634
}
635
636
void unload_bindings (const char *filename)
637
{
638
int i, j;
639
640
for (i = 0; i <= MAX_META; i++)
641
{
642
if (!keys[i])
643
continue;
644
645
for (j = 0; j < 256; j++)
646
if (KEY(i, j) && !strcmp(KEY(i, j)->filename, filename))
647
snew_key(i, j, NULL);
648
}
649
}
650
651
652
static void show_all_bindings (int meta)
653
{
654
int i, j, k;
655
656
if (meta == -1)
657
{
658
for (i = 0; i <= MAX_META; i++)
659
show_all_bindings(i);
660
return;
661
}
662
663
if (meta > MAX_META || !keys[meta])
664
return;
665
666
k = charset_size();
667
for (j = 0; j < k; j++)
668
if (KEY(meta, j) && KEY(meta, j)->key_index != 1)
669
show_binding(meta, j);
670
}
671
672
/* * * * * * * * * * * * * * PARSEKEY * * * * * * * * * * * * */
673
/* parsekeycmd: does the PARSEKEY command. */
674
BUILT_IN_COMMAND(parsekeycmd)
675
{
676
int i;
677
char *arg;
678
679
if ((arg = next_arg(args, &args)) != NULL)
680
{
681
int keyval = lookup_function(arg, &i);
682
683
switch (keyval)
684
{
685
case 0:
686
say("No such function %s", arg);
687
break;
688
case 1:
689
if (i < 0)
690
last_input_screen->meta_hit = -i;
691
else if (key_names[i].func)
692
key_names[i].func(0, args);
693
break;
694
default:
695
say("Ambigious function %s", arg);
696
break;
697
}
698
}
699
}
700
701
/* * * * * * * * * * * * * * RBIND * * * * * * * * * * * * * * */
702
/*
703
* rbindcmd: This is the /RBIND command. If you give it a bind action,
704
* it will show you all of the key bindings that have that action. You
705
* probably cannot lookup the action NOTHING as it is a magic action.
706
*/
707
BUILT_IN_COMMAND(rbindcmd)
708
{
709
int f;
710
char *arg;
711
int i, j;
712
int charsize = charset_size();
713
714
if ((arg = next_arg(args, &args)) == NULL)
715
return; /* No args is a no-op */
716
717
switch (lookup_function(arg, &f))
718
{
719
case 0:
720
say("No such function %s", arg);
721
return;
722
723
case 1:
724
break;
725
726
default:
727
say("Ambigious function %s", arg);
728
return;
729
}
730
731
for (i = 0; i <= MAX_META; i++)
732
{
733
if (!keys[i])
734
continue;
735
736
for (j = 0; j < charsize; j++)
737
if (KEY(i, j) && KEY(i, j)->key_index == f)
738
show_binding(i, j);
739
}
740
}
741
742
743
/* * * * * * * * * * * * * * BIND * * * * * * * * * * * * * */
744
static int grok_meta (const uc *ptr, const uc **end)
745
{
746
int meta = -1;
747
const uc * str;
748
749
/*
750
* Well, if it is going to be anywhere, META has to be out front,
751
* so lets slurp it up if its there.
752
*/
753
if (!my_strnicmp(ptr, "META", 4))
754
{
755
str = ptr = ptr + 4;
756
while (isdigit(*ptr))
757
ptr++;
758
if (*ptr == '_' && !my_strnicmp(ptr, "_CHARACTER", 10))
759
ptr = ptr + 10;
760
if (*ptr == '-')
761
ptr++;
762
meta = atol(str);
763
}
764
765
*end = ptr;
766
return meta;
767
}
768
769
/*
770
* copy_redux:
771
* This converts an ordinary sequence into something more suitable to
772
* work with, including the redux of ^X into X-64.
773
* You can then work with the sequence after processing.
774
*/
775
void copy_redux (const uc *orig, uc *result)
776
{
777
const uc *ptr;
778
*result = 0;
779
780
for (ptr = orig; ptr && *ptr; ptr++, result++)
781
{
782
if (*ptr != '^')
783
{
784
*result = *ptr;
785
continue;
786
}
787
788
ptr++;
789
switch (toupper(*ptr))
790
{
791
case 0: /* ^<nul> is ^ */
792
*result = '^';
793
return;
794
case '?': /* ^? is DEL */
795
*result = 0177;
796
break;
797
default:
798
if (toupper(*ptr) < 64)
799
{
800
say("Illegal key sequence: ^%c", *ptr);
801
*result = 0;
802
return;
803
}
804
*result = toupper(*ptr) - 64;
805
break;
806
}
807
}
808
*result = 0;
809
return;
810
}
811
812
/*
813
* find_meta_map: Finds a meta map that does not already contain a
814
* binding to the specified character.
815
*/
816
int find_meta_map (uc key)
817
{
818
int curr = MAX_META;
819
820
for (curr = MAX_META; curr > 4; curr--)
821
{
822
if (!keys[curr])
823
return curr;
824
825
if (!KEY(curr, key))
826
return curr;
827
}
828
829
resize_metamap(curr_keys_size + 1);
830
return MAX_META; /* Well, its empty now */
831
}
832
833
/*
834
* Purpose:
835
* To make sure that the key sequence X is valid upon return.
836
* Composition of X is: [<key>]*<key>
837
* Where <key> is an ascii char > 32, or a caret followed by an ascii char.
838
*
839
* First, remove the last character
840
* Second, remove the leading part of X that is a valid meta descriptor
841
*
842
* At this point, we have <META> + [<unbound-key>]* + <final-key>
843
*
844
* If unbound-key is present, then we have to bind it. The first thing to
845
* do is find a place where <final-key> can be stashed. Look for the highest
846
* metamap that has an open spot for <final-key>
847
*
848
* Now we have <META> + [<unbound-key>]* + <unbound-key> + <final-key>
849
* And we now know what meta map the first three parts have to conclude to.
850
* So that is the return value.
851
*
852
* Now we need to build up to that. Repeat this process until there is
853
* nothing left in the unbound-key segment.
854
*/
855
/*
856
* A lot of magic goes on in this function. The general purpose of this
857
* function is to take a "key-description" of any form, and canonicalize
858
* it down into a resulting meta map (which is the return value), and return
859
* the final character in 'term'. Older algorithms only allowed you to
860
* specify META(X)-(Y), where X is the meta value to be returned and Y is
861
* the character, and anything else was an error. Now we allow you to specify
862
* any arbitrary string -- if the leading part of the string is already bound
863
* to a META key, then we can deal with that. If the leading part of the
864
* string is NOT bound to anything in particular, then we will bind it FOR
865
* you, and the resulting meta state is returned. This allows things like
866
* this to work:
867
*
868
* /BIND META2-C BIND-ACTION (Specify a meta map directly)
869
* /BIND ^[[A BIND-ACTION (^[[ is bound to META2 by default)
870
* /BIND ^[[11~ BIND-ACTION (Force us to make suer ^[[11 is bound
871
* to a meta map before returning.)
872
*/
873
static int parse_key (const uc *sequence, uc *term)
874
{
875
uc *copy;
876
uc *end;
877
int return_meta = 0;
878
int meta;
879
uc last_character;
880
uc terminal_character;
881
int last;
882
int somethingN;
883
#ifdef GUI
884
int mouse;
885
#endif
886
887
/*
888
* Make a local copy of the string to be bound. Redux all of
889
* the ^x modifers to their literal control characters.
890
*/
891
copy = alloca(strlen(sequence) + 4);
892
copy_redux(sequence, copy);
893
end = copy + strlen(copy) - 1;
894
895
#ifdef GUI
896
for( mouse = 0; mouse < MAX_MOUSE; mouse++)
897
{
898
if (!my_strnicmp(sequence, mouse_actions[mouse], strlen(mouse_actions[mouse])))
899
{
900
*term=(char)mouse;
901
return MAX_META;
902
}
903
}
904
#endif
905
906
if (x_debug & DEBUG_AUTOKEY)
907
yell("Starting with COPY := [%s]", copy);
908
/*
909
* Remove any leading META description
910
*/
911
if ((meta = grok_meta(copy, (const uc **)&copy)) == -1)
912
meta = 0;
913
914
if (x_debug & DEBUG_AUTOKEY)
915
yell("After META grokked, COPY := [%s]", copy);
916
917
/*
918
* Remove any leading characters that also comprise a META
919
* description
920
*/
921
while (copy[0] && copy[1])
922
{
923
if (keys[meta] && KEY(meta, *copy) &&
924
KEY(meta, *copy)->key_index < 0)
925
{
926
meta = -(KEY(meta, *copy)->key_index);
927
copy++;
928
if (x_debug & DEBUG_AUTOKEY)
929
{
930
yell("First character of COPY switches to meta [%d]", meta);
931
yell("After META grokked, COPY := [%s]", copy);
932
}
933
continue;
934
}
935
break;
936
}
937
938
if (x_debug & DEBUG_AUTOKEY)
939
yell("After ALL META grokked, COPY := [%s]", copy);
940
941
/*
942
* Check to see if the entire sequence was just a meta modifier
943
* or if it is a META-KEY modifier. Either way, we're done.
944
*/
945
if (!copy[0] || !copy[1])
946
{
947
*term = copy[0];
948
return meta;
949
}
950
951
/*
952
* Right now the input boils down to this:
953
*
954
* input := SOME_CHARACTERS + TERMINAL_CHARACTER + LAST_CHARACTER
955
* SOME_CHARACTERS := <key>*
956
* TERMINAL_CHARACTER := <key>
957
* LAST_CHARACTER := <key>
958
*
959
* The previous check assures that 'terminal character' is not
960
* an empty value at this point.
961
*/
962
last_character = *end;
963
*end-- = 0;
964
terminal_character = *end;
965
*end-- = 0;
966
967
if (x_debug & DEBUG_AUTOKEY)
968
{
969
yell("Starting to work on the string:");
970
yell("SOME_CHARACTERS := [%s] (%d)", copy, strlen(copy));
971
yell("TERMINAL_CHARACTER := [%c]", terminal_character);
972
yell("LAST_CHARACTER := [%c]", last_character);
973
}
974
975
976
/*
977
* Our ultimate goal is to return when the operation:
978
* /bind META<something>-LAST_CHARACTER <binding>
979
* will succeed. So we need to find a place to put LAST_CHARACTER.
980
*/
981
last = return_meta = find_meta_map(last_character);
982
if (x_debug & DEBUG_AUTOKEY)
983
{
984
yell("FIND_META_MAP says we can put [%c] in META [%d]",
985
last_character, return_meta);
986
}
987
988
/*
989
* So now we need to work backwards through the string linking
990
* each of the characters to the next one. Starting with
991
* TERMINAL_CHARACTER, we find a meta map where that can be linked
992
* from (that map is somethingN1). We then do:
993
*
994
* /bind META<somethingN1>-TERMINAL_CHARACTER META<LAST>
995
*
996
* Where 'last' is the most previous meta map we linked to, starting
997
* with 'something'.
998
*/
999
while (*copy)
1000
{
1001
if (x_debug & DEBUG_AUTOKEY)
1002
{
1003
yell("COPY: [%s] (%d)", copy, strlen(copy));
1004
yell("Now we are going to bind the [%c] character to meta [%d] somehow.",
1005
terminal_character, last);
1006
}
1007
1008
/*
1009
* <something> is any meta map such that:
1010
* /bind META<somethingN>-[TERMINAL CHARACTER] META<something>
1011
*/
1012
somethingN = find_meta_map(terminal_character);
1013
if (x_debug & DEBUG_AUTOKEY)
1014
yell("FIND_META_MAP says we can do this in META [%d]", somethingN);
1015
1016
new_key(somethingN, terminal_character, -last, 1, NULL);
1017
show_binding(somethingN, terminal_character);
1018
1019
/*
1020
* Now we walk backwards in the string: 'last' now becomes
1021
* the meta map we just linked, and we pop TERMINAL_CHARACTER
1022
* off the end of SOME_CHARACTERS. We repeat this until
1023
* SOME_CHARACTERS is empty.
1024
*/
1025
last = somethingN;
1026
terminal_character = *end;
1027
*end-- = 0;
1028
}
1029
1030
/*
1031
* Make the final link from the initial meta state to our newly
1032
* constructed chain...
1033
*/
1034
new_key(meta, terminal_character, -last, 1, NULL);
1035
show_binding(meta, terminal_character);
1036
1037
/*
1038
* Return the interesting information
1039
*/
1040
*term = last_character;
1041
return return_meta;
1042
1043
#if 0
1044
/* The rest of this isnt finished, hense is unsupported */
1045
say("The bind cannot occur because the character sequence to bind contains a leading substring that is bound to something else.");
1046
return -1;
1047
#endif
1048
}
1049
1050
/*
1051
* bindcmd: The /BIND command. The general syntax is:
1052
*
1053
* /BIND ([key-descr] ([bind-command] ([args])))
1054
* Where:
1055
* KEY-DESCR := ([^]C | META[num])
1056
* BIND-COMMAND := <Any string in the key_names lookup table>
1057
*
1058
* If given no arguments, this command shows all non-empty bindings
1059
* current registered.
1060
*
1061
* If given one argument, that argument is to be a description of a valid
1062
* key sequence. The command will show the binding of that sequence.
1063
*
1064
* If given two arguments, the first argument is to be a description of a
1065
* valid key sequence and the second argument is to be a valid binding
1066
* command followed by any optionally appropriate arguments. The key
1067
* sequence is then bound to that action.
1068
*
1069
* The special binding command "NOTHING" actually unbinds the key.
1070
*/
1071
BUILT_IN_COMMAND(bindcmd)
1072
{
1073
uc *key,
1074
*function;
1075
uc *newkey;
1076
int meta;
1077
uc dakey;
1078
int bi_index;
1079
int cnt,
1080
i;
1081
1082
/*
1083
* See if they specified a key argument. If they didnt, show all
1084
* binds and return
1085
*/
1086
if ((key = new_next_arg(args, &args)) == NULL)
1087
{
1088
show_all_bindings(-1);
1089
return;
1090
}
1091
1092
/*
1093
* Grok any flags (only one, for now)
1094
*/
1095
if (*key == '-')
1096
{
1097
if (!my_strnicmp(key + 1, "DEFAULTS", 1))
1098
{
1099
init_keys();
1100
init_keys2();
1101
}
1102
return;
1103
}
1104
1105
1106
/*
1107
* Grok the key argument and see what we can make of it
1108
* If there is an error at this point, dont continue.
1109
* Most of the work is done here.
1110
*/
1111
1112
newkey = get_term_capability(key, 0, 1);
1113
if ((meta = parse_key(newkey ? newkey : key, &dakey)) == -1)
1114
if (!newkey || (parse_key(key, &dakey) == -1))
1115
return;
1116
1117
/*
1118
* See if they specified an action argument. If they didnt, then
1119
* check to see if they specified /bind METAX or if they specified
1120
* /bind <char sequence>, and output as is appropriate.
1121
*/
1122
if ((function = next_arg(args, &args)) == NULL)
1123
{
1124
/* They did /bind ^C */
1125
if (dakey)
1126
show_binding(meta, dakey);
1127
1128
/* They did /bind meta2 */
1129
else
1130
show_all_bindings(meta);
1131
1132
return;
1133
}
1134
1135
/*
1136
* Look up the action they want to take. If it is invalid, tell
1137
* them so, if it is ambiguous, show the possible choices, and if
1138
* if it valid, then actually do the bind action. Note that if we
1139
* do the bind, we do a show() so the user knows we took the action.
1140
*/
1141
switch ((cnt = lookup_function(function, &bi_index)))
1142
{
1143
case 0:
1144
say("No such function: %s", function);
1145
break;
1146
case 1:
1147
if (meta < 1 || meta > MAX_META)
1148
meta = 0;
1149
new_key(meta, dakey, bi_index, 1, *args ? args : NULL);
1150
show_binding(meta, dakey);
1151
break;
1152
default:
1153
say("Ambiguous function name: %s", function);
1154
for (i = 0; i < cnt; i++, bi_index++)
1155
put_it("%s", key_names[bi_index].name);
1156
break;
1157
}
1158
}
1159
1160
/* * * * * * * * * * * BINDING ACTIONS * * * * * * * * * */
1161
/* I hate typedefs... */
1162
1163
/*
1164
* lookup_function: When you want to convert a "binding" name (such as
1165
* BACKSPACE or SELF_INSERT) over to its offset in the binding lookup table,
1166
* you must call this function to retreive that offset. The first argument
1167
* is the name you want to look up, and the second argument is where the
1168
* offset is to be stored.
1169
*
1170
* Return value: (its tricky)
1171
* -1 -- The name is a META binding that is invalid.
1172
* Zero -- The name is not a valid binding name.
1173
* One -- The name is a valid, unambiguous binding name.
1174
* If it is a META binding, lf_index will be negative,
1175
* Otherwise, lf_index will be positive.
1176
* Other -- The name is an ambiguous (therefore invalid) binding name.
1177
*
1178
* In the case of a return value of any positive value, "lf_index" will be
1179
* set to the first item that matches the 'name'. For all other return
1180
* values, "lf_index" will have the value -1.
1181
*/
1182
static int lookup_function (const uc *orig_name, int *lf_index)
1183
{
1184
int len,
1185
cnt,
1186
i;
1187
uc *name, *breakage;
1188
1189
if (!orig_name)
1190
{
1191
*lf_index = 0;
1192
return 1;
1193
}
1194
1195
breakage = name = LOCAL_COPY(orig_name);
1196
upper(name);
1197
len = strlen(name);
1198
1199
*lf_index = -1;
1200
1201
/* Handle "META" descriptions especially. */
1202
if (!strncmp(name, "META", 4))
1203
{
1204
const uc * endp;
1205
int meta;
1206
1207
if ((meta = grok_meta(name, &endp)) < 0)
1208
return meta;
1209
else
1210
{
1211
*lf_index = -meta;
1212
return 1;
1213
}
1214
}
1215
1216
for (cnt = 0, i = 0; i < NUMBER_OF_FUNCTIONS; i++)
1217
{
1218
if (strncmp(name, key_names[i].name, len) == 0)
1219
{
1220
cnt++;
1221
if (*lf_index == -1)
1222
*lf_index = i;
1223
}
1224
}
1225
if (*lf_index == -1)
1226
return 0;
1227
if (strcmp(name, key_names[*lf_index].name) == 0)
1228
return 1;
1229
else
1230
return cnt;
1231
}
1232
1233
1234
/* I dont know where this belongs. */
1235
/*
1236
* display_key: Given a (possibly unprintable) unsigned character 'c',
1237
* convert that character into a printable string. For characters less
1238
* than 32, and the character 127, they will be converted into the "control"
1239
* sequence by having a prepended caret ('^'). Other characters will be
1240
* left alone. The return value belongs to the function -- dont mangle it.
1241
*/
1242
static uc * display_key (uc c)
1243
{
1244
static uc key[3];
1245
1246
key[2] = (char) 0;
1247
if (c < 32)
1248
{
1249
key[0] = '^';
1250
key[1] = c + 64;
1251
}
1252
else if (c == '\177')
1253
{
1254
key[0] = '^';
1255
key[1] = '?';
1256
}
1257
else
1258
{
1259
key[0] = c;
1260
key[1] = (char) 0;
1261
}
1262
return (key);
1263
}
1264
1265
char *convert_to_keystr(char *key)
1266
{
1267
int ret, loc;
1268
static char keyloc[80];
1269
ret = lookup_function(key, &loc);
1270
*keyloc = 0;
1271
if (ret == 1)
1272
{
1273
char meta_str[8];
1274
int i, j;
1275
int charsize = charset_size();
1276
*meta_str = 0;
1277
1278
for (i = 0; i <= MAX_META; i++)
1279
{
1280
if (!keys[i])
1281
continue;
1282
for (j = 0; j < charsize; j++)
1283
if (KEY(i, j) && KEY(i, j)->key_index == loc)
1284
{
1285
if (i > 0)
1286
sprintf(meta_str, "META%d-", i);
1287
sprintf(keyloc, "%s%s", meta_str, display_key(j));
1288
return keyloc;
1289
}
1290
}
1291
}
1292
return keyloc;
1293
}
1294
1295
/* * * * * * * * * * * * * * * * * * INITIALIZATION * * * * * * * * * * * */
1296
/*
1297
* This is where you put all the default key bindings. This is a lot
1298
* simpler, just defining those you need, instead of all of them, isnt
1299
* it? And it takes up so much less memory, too...
1300
*/
1301
void init_keys (void)
1302
{
1303
int i;
1304
1305
/*
1306
* Make sure the meta map is big enough to hold all these bindings.
1307
*/
1308
remove_bindings();
1309
resize_metamap(40); /* Whatever. */
1310
1311
/*
1312
* All the "default" bindings are self_insert unless we bind
1313
* them differently
1314
*/
1315
for (i = 1; i <= 255; i++)
1316
snew_key(0, i, "SELF_INSERT");
1317
1318
/* "default" characters that arent self_insert */
1319
snew_key(0, 1, "BEGINNING_OF_LINE"); /* ^A */
1320
snew_key(0, 2, "BOLD"); /* ^B */
1321
snew_key(0, 4, "DELETE_CHARACTER"); /* ^D */
1322
snew_key(0, 5, "CHANGE_TO_SPLIT"); /* ^E */
1323
snew_key(0, 6, "WHOLEFT"); /* ^F */
1324
snew_key(0, 8, "BACKSPACE"); /* ^H (delete) */
1325
1326
snew_key(0, 9, "TAB_COMPLETION"); /* ^I (tab) */
1327
snew_key(0, 10, "SEND_LINE"); /* ^J (enter) */
1328
snew_key(0, 11, "JOIN_LAST_INVITE"); /* ^K */
1329
snew_key(0, 12, "REFRESH_SCREEN"); /* ^L (linefeed) */
1330
snew_key(0, 13, "SEND_LINE"); /* ^M (return) */
1331
snew_key(0, 14, "QUOTE_CHARACTER"); /* ^N */
1332
snew_key(0, 15, "IGNORE_NICK"); /* ^O */
1333
snew_key(0, 16, "BACKWARD_HISTORY"); /* ^P */
1334
1335
snew_key(0, 17, "QUOTE_CHARACTER"); /* ^Q */
1336
snew_key(0, 18, "NICK_COMPLETION"); /* ^R */
1337
snew_key(0, 19, "TOGGLE_STOP_SCREEN"); /* ^S */
1338
snew_key(0, 20, "TRANSPOSE_CHARACTERS"); /* ^T */
1339
snew_key(0, 21, "ERASE_LINE"); /* ^U */
1340
snew_key(0, 22, "REVERSE"); /* ^V */
1341
snew_key(0, 23, "META2_CHARACTER"); /* ^W */
1342
snew_key(0, 24, "SWITCH_CHANNELS"); /* ^X */
1343
1344
snew_key(0, 25, "YANK_FROM_CUTBUFFER"); /* ^Y */
1345
#ifdef ALLOW_STOP_IRC
1346
#ifndef PUBLIC_ACCESS
1347
snew_key(0, 26, "STOP_IRC"); /* ^Z */
1348
#endif
1349
#endif
1350
snew_key(0, 27, "META1_CHARACTER"); /* ^[ (escape) */
1351
snew_key(0, 29, "AUTOREPLY"); /* ^] */
1352
snew_key(0, 31, "UNDERLINE"); /* ^_ */
1353
1354
snew_key(0, 127, "BACKSPACE"); /* ^? (delete) */
1355
1356
/*
1357
* european keyboards (and probably others) use the eigth bit
1358
* for extended characters. Having these keys bound by default
1359
* causes them lots of grief, so unless you really want to use
1360
* these, they are commented out.
1361
*/
1362
#ifdef EMACS_KEYBINDS
1363
snew_key(0, 188, "SCROLL_START");
1364
snew_key(0, 190, "SCROLL_END");
1365
snew_key(0, 226, "BACKWARD_WORD");
1366
snew_key(0, 228, "DELETE_NEXT_WORD");
1367
snew_key(0, 229, "SCROLL_END");
1368
snew_key(0, 230, "FORWARD_WORD");
1369
snew_key(0, 232, "DELETE_PREVIOUS_WORD");
1370
snew_key(0, 255, "DELETE_PREVIOUS_WORD");
1371
#endif
1372
1373
/* meta 1 characters */
1374
snew_key(1, 27, "COMMAND_COMPLETION");
1375
snew_key(1, 46, "CLEAR_SCREEN");
1376
snew_key(1, 60, "SCROLL_START");
1377
snew_key(1, 62, "SCROLL_END");
1378
snew_key(1, 79, "META2_CHARACTER");
1379
snew_key(1, 91, "META2_CHARACTER");
1380
snew_key(1, 98, "BACKWARD_WORD");
1381
snew_key(1, 100, "DELETE_NEXT_WORD");
1382
snew_key(1, 101, "SCROLL_END");
1383
snew_key(1, 102, "FORWARD_WORD");
1384
snew_key(1, 104, "DELETE_PREVIOUS_WORD");
1385
snew_key(1, 110, "SCROLL_FORWARD");
1386
snew_key(1, 112, "SCROLL_BACKWARD");
1387
snew_key(1, 127, "DELETE_PREVIOUS_WORD");
1388
1389
snew_key(1, '1', "WINDOW_SWAP_1");
1390
snew_key(1, '2', "WINDOW_SWAP_2");
1391
snew_key(1, '3', "WINDOW_SWAP_3");
1392
snew_key(1, '4', "WINDOW_SWAP_4");
1393
snew_key(1, '5', "WINDOW_SWAP_5");
1394
snew_key(1, '6', "WINDOW_SWAP_6");
1395
snew_key(1, '7', "WINDOW_SWAP_7");
1396
snew_key(1, '8', "WINDOW_SWAP_8");
1397
snew_key(1, '9', "WINDOW_SWAP_9");
1398
snew_key(1, '0', "WINDOW_SWAP_10");
1399
1400
/* meta 2 characters */
1401
#ifdef ALLOW_STOP_IRC
1402
#ifndef PUBLIC_ACCESS
1403
snew_key(2, 26, "STOP_IRC");
1404
#endif
1405
#endif
1406
1407
snew_key(2, 110, "SWAP_NEXT_WINDOW");
1408
snew_key(2, 112, "PREVIOUS_WINDOW");
1409
1410
#ifdef __EMX__
1411
/* meta 3 characters */
1412
snew_key(2, '[', "META3_CHARACTER");
1413
snew_key(2, '1', "META3_CHARACTER");
1414
1415
snew_key(1, 71, "NEW_BEGINNING_OF_LINE");
1416
snew_key(1, 83, "TOGGLE_CLOAK");
1417
snew_key(1, 79, "NEW_SCROLL_END");
1418
snew_key(1, 73, "NEW_SCROLL_BACKWARD");
1419
snew_key(1, 81, "NEW_SCROLL_FORWARD");
1420
1421
snew_key(2, '?', "WINDOW_HELP");
1422
snew_key(2, '+', "WINDOW_GROW_ONE");
1423
snew_key(2, '-', "WINDOW_SHRINK_ONE");
1424
snew_key(2, 'm', "WINDOW_MOVE");
1425
snew_key(2, 'l', "WINDOW_LIST");
1426
snew_key(2, 'k', "WINDOW_KILL");
1427
snew_key(2, 'b', "WINDOW_BALANCE");
1428
snew_key(2, 'h', "WINDOW_HIDE");
1429
1430
snew_key(2, '[', "META3_CHARACTER");
1431
snew_key(2, '1', "META3_CHARACTER");
1432
1433
#else /* __EMX__ */
1434
snew_key(2, '?', "WINDOW_HELP");
1435
snew_key(2, '+', "WINDOW_GROW_ONE");
1436
snew_key(2, '-', "WINDOW_SHRINK_ONE");
1437
snew_key(2, 'm', "WINDOW_MOVE");
1438
snew_key(2, 'l', "WINDOW_LIST");
1439
snew_key(2, 'k', "WINDOW_KILL");
1440
snew_key(2, 'b', "WINDOW_BALANCE");
1441
snew_key(2, 'h', "WINDOW_HIDE");
1442
snew_key(2, '[', "META3_CHARACTER");
1443
snew_key(2, 70, "SCROLL_START"); /* Freebsd home */
1444
snew_key(2, 71, "SCROLL_FORWARD"); /* Freebsd pgdown */
1445
snew_key(2, 72, "SCROLL_END"); /* Freebsd end */
1446
snew_key(2, 73, "SCROLL_BACKWARD"); /* Freebsd pgup */
1447
snew_key(2, '1', "META32_CHARACTER");
1448
snew_key(2, '4', "META33_CHARACTER");
1449
snew_key(2, '5', "META30_CHARACTER");
1450
snew_key(2, '6', "META31_CHARACTER");
1451
#endif
1452
1453
/* meta 4 characters -- vi key mappings */
1454
snew_key(4, 8, "BACKWARD_CHARACTER");
1455
snew_key(4, 32, "FORWARD_CHARACTER");
1456
snew_key(4, 65, "META4");
1457
snew_key(4, 72, "BACKWARD_CHARACTER");
1458
snew_key(4, 73, "META4");
1459
snew_key(4, 74, "FORWARD_HISTORY");
1460
snew_key(4, 75, "BACKWARD_HISTORY");
1461
snew_key(4, 76, "FORWARD_CHARACTER");
1462
snew_key(4, 88, "DELETE_CHARACTER");
1463
snew_key(4, 97, "META4");
1464
snew_key(4, 104, "BACKWARD_CHARACTER");
1465
snew_key(4, 105, "META4");
1466
snew_key(4, 106, "FORWARD_HISTORY");
1467
snew_key(4, 107, "BACKWARD_HISTORY");
1468
snew_key(4, 108, "FORWARD_CHARACTER");
1469
snew_key(4, 120, "DELETE_CHARACTER");
1470
1471
/* I used 30-something to keep them out of others' way */
1472
snew_key(30, '~', "SCROLL_BACKWARD");
1473
snew_key(31, '~', "SCROLL_FORWARD");
1474
snew_key(32, '~', "SCROLL_START");
1475
snew_key(33, '~', "SCROLL_END");
1476
}
1477
1478
#define LKEY(x, y) \
1479
{ \
1480
char *l = get_term_capability(#x, 0, 1); \
1481
if (l) \
1482
snew_key_from_str(l, #y); \
1483
}
1484
1485
void init_keys2 (void)
1486
{
1487
/* keys bound from terminfo/termcap */
1488
LKEY(key_up, BACKWARD_HISTORY)
1489
LKEY(key_down, FORWARD_HISTORY)
1490
LKEY(key_left, BACKWARD_CHARACTER)
1491
LKEY(key_right, FORWARD_CHARACTER)
1492
LKEY(key_ppage, SCROLL_BACKWARD)
1493
LKEY(key_npage, SCROLL_FORWARD)
1494
LKEY(key_home, SCROLL_START)
1495
LKEY(key_end, SCROLL_END)
1496
LKEY(key_ic, TOGGLE_INSERT_MODE)
1497
/*LKEY(key_dc, DELETE_CHARACTER)*/
1498
LKEY(key_f1, CHELP)
1499
LKEY(key_f2, CHANNEL_CHOPS)
1500
LKEY(key_f3, CHANNEL_NONOPS)
1501
#ifdef WANT_CDCC
1502
LKEY(key_f4, CDCC_PLIST)
1503
#endif
1504
LKEY(key_f5, DCC_PLIST)
1505
LKEY(key_f6, DCC_STATS)
1506
LKEY(key_dc, TOGGLE_CLOAK)
1507
}
1508
1509
1510
void disable_stop(void)
1511
{
1512
snew_key(0, 26, "SELF_INSERT");
1513
}
1514
1515