source: golgotha/src/i4/device/key_man.cc @ 80

Last change on this file since 80 was 80, checked in by Sam Hocevar, 12 years ago
  • Adding the Golgotha source code. Not sure what's going to be interesting in there, but since it's all public domain, there's certainly stuff to pick up.
File size: 11.4 KB
Line 
1/********************************************************************** <BR>
2  This file is part of Crack dot Com's free source code release of
3  Golgotha. <a href="http://www.crack.com/golgotha_release"> <BR> for
4  information about compiling & licensing issues visit this URL</a>
5  <PRE> If that doesn't help, contact Jonathan Clark at
6  golgotha_source@usa.net (Subject should have "GOLG" in it)
7***********************************************************************/
8
9#include "device/key_man.hh"
10#include "device/event.hh"
11#include "file/file.hh"
12#include "error/alert.hh"
13#include "device/kernel.hh"
14#include "memory/growheap.hh"
15
16i4_key_man_class i4_key_man;
17
18i4_key_man_class::i4_key_man_class()
19{
20  loaded=0;
21  active_list=0;
22  context_list=0;
23  command_list=0;
24  char_heap=0;
25  memset(keys, 0, sizeof(keys));
26}
27
28
29// end commands no longer appropriate for for the current modifiers
30void i4_key_man_class::end_actives(int matches_key, i4_time_class &time)
31
32  key_item *last=0;
33  for (key_item *j=active_list; j; )
34  {
35    if (j->modifier_flags!=key_modifiers_pressed || j->key==matches_key)
36    {
37      key_item *q=j;
38      j=j->next_active;
39
40      if (last)
41        last->next_active=q->next_active;
42      else
43        active_list=active_list->next_active;
44     
45      i4_end_command_event_class kcmd( (*command_list)[q->command_id], q->command_id, time);
46      send_event_to_agents(&kcmd, FLAG_END_COMMAND);
47
48      q->command_active=0;
49    }
50    else
51    {
52      last=j;
53      j=j->next_active;
54    }
55  }
56}
57
58
59void i4_key_man_class::get_modifiers(int k_mod)
60{
61  if (k_mod)                     // turn left & right into same thing
62  {
63    if (k_mod & I4_MODIFIER_SHIFT)
64      k_mod=I4_MODIFIER_SHIFT;
65    if (k_mod & I4_MODIFIER_CTRL)
66      k_mod=I4_MODIFIER_CTRL;
67    if (k_mod & I4_MODIFIER_ALT)
68      k_mod=I4_MODIFIER_ALT;
69
70    // don't uses these modifiers
71    if (k_mod & (I4_MODIFIER_WINDOWS | I4_MODIFIER_CAPS | I4_MODIFIER_NUMLOCK))
72      k_mod &= ~(I4_MODIFIER_WINDOWS | I4_MODIFIER_CAPS | I4_MODIFIER_NUMLOCK);
73  }
74
75  if (context_list)
76    k_mod &= ~((*context_list)[context_id].modifiers_taken);
77
78
79  key_modifiers_pressed=k_mod;
80}
81
82
83void i4_key_man_class::add_active(i4_key_man_class::key_item *i, i4_time_class &time)
84{
85  if (!i->command_active)
86  {
87    i->command_active=1;
88    i->next_active=active_list;
89    active_list=i;
90
91    i4_do_command_event_class kcmd( (*command_list)[i->command_id], i->command_id, time);
92    send_event_to_agents(&kcmd, FLAG_DO_COMMAND);
93  }
94}
95
96
97void i4_key_man_class::receive_event(i4_event *ev)
98{
99  if (!loaded) return ;
100
101  if (ev->type()==i4_event::KEY_PRESS)
102  {
103    CAST_PTR(kev, i4_key_press_event_class, ev);
104    int old_modifiers=key_modifiers_pressed;
105
106    get_modifiers(kev->modifiers);
107
108    if (old_modifiers!=key_modifiers_pressed)
109    {
110      for (key_item *i=active_list; i; i=i->next_active)
111      {
112        for (key_item *j=keys[i->key]; j; j=j->next)
113        {
114          if (j!=i && j->modifier_flags==key_modifiers_pressed &&
115              (j->context_mask&(1<<context_id)))
116            add_active(j, kev->time);
117
118        }
119      }
120
121      end_actives(-1, kev->time);
122    }
123
124    for (key_item *i=keys[kev->key_code]; i; i=i->next)
125      if (key_modifiers_pressed == i->modifier_flags && (i->context_mask& (1<<context_id)))
126        add_active(i, kev->time);
127
128  } else if (ev->type()==i4_event::KEY_RELEASE)
129  {
130    CAST_PTR(kev, i4_key_press_event_class, ev);
131
132    int old_modifiers=key_modifiers_pressed;
133    get_modifiers(kev->modifiers);
134
135    if (old_modifiers!=key_modifiers_pressed)
136    {
137      for (key_item *i=active_list; i; i=i->next_active)
138      {
139        for (key_item *j=keys[i->key]; j; j=j->next)
140        {
141          if (j!=i && j->modifier_flags==key_modifiers_pressed &&
142              (j->context_mask & (1<<context_id)))
143            add_active(j, kev->time);
144
145        }
146      }
147
148      end_actives(-1, kev->time);
149    }
150
151
152    end_actives(kev->key_code, kev->time);   
153  }
154}
155
156static i4_bool is_white(char *s)
157{
158  if (*s==' ' || *s=='\n' || *s=='\r' || *s=='\t')
159    return i4_T;
160  else return i4_F;
161}
162
163static void skip_white(char *&s)
164{
165  while (*s && is_white(s)) s++;
166}
167
168static i4_bool i4_go_key_start(char *&s)
169{
170  while (*s && *s!='(')
171  {
172    if (*s=='#')
173    {
174      while (*s && (*s!='\n' && *s!='\r'))
175        s++;
176    } else s++;
177  }
178 
179  if (*s)
180  {
181    while (*s && *s!=' ') s++;
182    skip_white(s);
183    return i4_T;
184  }
185  else return i4_F; 
186}
187
188static char get_char(char *&s)
189{
190  if (*s=='\\')
191  {
192    s+=2;
193    if (s[-1]=='n') return '\n';
194    if (s[-1]=='r') return '\r';
195    if (s[-1]=='t') return '\t';
196    if (s[-1]=='b') return '\b';   
197    if (s[-1]=='\\') return '\\';   
198  }
199  else
200  {
201    s++;
202    return s[-1];
203  }
204  return '\\';
205}
206
207static void i4_read_str(char *&s, char *buf)
208{
209  skip_white(s);
210  if (s[0]=='"')
211  {
212    s++;
213    while (*s && *s!='"')     
214      *(buf++)=get_char(s);
215    *buf=0;
216    s++;
217  }
218  else
219  {
220    *(buf++)=*(s++);
221    while (*s && !is_white(s) && *s!=')')
222      *(buf++)=get_char(s);
223    *buf=0;
224  }
225}
226
227int i4_key_man_class::acquire_modifiers_for_contexts(int context_mask, int mod, char *key_name)
228{
229  int c=context_mask, i=0, total=0, skip_this_key=0;
230  while (c)
231  {
232    if (c&1)
233    {
234      if (((*context_list)[i].modifiers_used & mod))
235      {
236        i4_alert(i4gets("modifier_in_use"),200, key_name);
237        return 0;
238      }
239      else
240      {
241        (*context_list)[i].modifiers_used |= mod;
242        (*context_list)[i].modifiers_taken |= mod;
243      }
244    }
245
246    c>>=1;
247    i++;
248  }
249 
250  return 1;
251}
252
253int i4_key_man_class::use_modifiers_for_contexts(int context_mask, int mod, char *key_name)
254{
255 int c=context_mask, i=0;
256
257  while (c)
258  {
259    if (c&1)
260    {
261      if (((*context_list)[i].modifiers_taken & mod))
262      {
263        i4_alert(i4gets("modifier_in_use"),200, key_name);
264        return 0;
265      }
266      else
267        (*context_list)[i].modifiers_used |= mod;
268    }
269
270    c>>=1;
271    i++;
272  }
273
274  return 1;
275}
276
277i4_bool i4_key_man_class::load(const i4_const_str &filename)
278{
279  check_init();
280  i4_file_class *fp=i4_open(filename);
281  if (!fp) return i4_F;
282
283  int size=fp->size();
284  void *mem=i4_malloc(size+1,"");
285  fp->read(mem,size);
286  delete fp;
287 
288  char *c=(char *)mem;
289  c[size]=0;
290
291  char tmp[256];
292 
293  int x=0;
294  while (i4_go_key_start(c))
295  {
296    w16 mod;
297    i4_key key;
298    char key_name[256],cmd[256];
299    int skip_key=0;
300
301    x++;
302    i4_read_str(c,key_name);   
303    if (!i4_find_key(i4_const_str(key_name), key, mod))
304    {
305      i4_alert(i4gets("no_key"),100, key_name, &filename);
306      skip_key=1;
307    }
308
309    i4_read_str(c,cmd);
310    int id=get_command_id(cmd);
311
312    int context_mask=0;
313    do
314    {
315      i4_read_str(c,tmp);
316      if (tmp[0] && tmp[0]!=')')
317        context_mask|=(1<<get_context_id(tmp));
318    } while (tmp[0]!=')' && tmp[0]);
319
320    if (key==0 && mod!=0 && !skip_key)   // they want a CTRL-ALT-SHIFT type key
321    {
322      if (acquire_modifiers_for_contexts(context_mask, mod, key_name))
323      {
324
325        if (mod & I4_MODIFIER_CTRL)     
326        {
327          keys[I4_CTRL_L]=new key_item(context_mask, id, 0, I4_CTRL_L, keys[I4_CTRL_L]);
328          keys[I4_CTRL_R]=new key_item(context_mask, id, 0, I4_CTRL_R, keys[I4_CTRL_R]);
329        }
330
331        if (mod & I4_MODIFIER_ALT)     
332        {
333          keys[I4_ALT_L]=new key_item(context_mask, id, 0, I4_ALT_L, keys[I4_ALT_L]);
334          keys[I4_ALT_R]=new key_item(context_mask, id, 0, I4_ALT_R, keys[I4_ALT_R]);
335        }
336
337        if (mod & I4_MODIFIER_SHIFT)     
338        {
339          keys[I4_SHIFT_L]=new key_item(context_mask, id, 0, I4_SHIFT_L, keys[I4_SHIFT_L]);
340          keys[I4_SHIFT_R]=new key_item(context_mask, id, 0, I4_SHIFT_R, keys[I4_SHIFT_R]);
341        }
342
343        if (mod & I4_MODIFIER_WINDOWS)
344          keys[I4_COMMAND]=new key_item(context_mask, id, 0, I4_COMMAND, keys[I4_COMMAND]);
345
346        if (mod & I4_MODIFIER_CAPS)
347          keys[I4_CAPS]=new key_item(context_mask, id, 0, I4_CAPS, keys[I4_CAPS]);
348
349        if (mod & I4_MODIFIER_NUMLOCK)
350          keys[I4_NUM_LOCK]=new key_item(context_mask, id, 0, I4_NUM_LOCK, keys[I4_NUM_LOCK]);
351      }
352    }
353    else if (!skip_key)
354    {
355      if (use_modifiers_for_contexts(context_mask, mod, key_name))
356      {
357        // make sure the key isn't already assigned
358        for (key_item *i=keys[key]; i; i=i->next)
359        {       
360          if (i->modifier_flags==mod && (i->context_mask & context_mask))
361            i4_error("attempting to assign command %s but key %s (%d) already command %s",
362                     (*command_list)[i->command_id], key_name, key, (*command_list)[id]);
363
364        }
365
366        keys[key]=new key_item(context_mask, id, mod, key, keys[key]);   
367      }
368    }
369  }
370
371  i4_free(mem);
372  loaded=i4_T;
373  return i4_T;
374}
375
376
377void i4_key_man_class::uninit()
378{
379  if (!command_list) return;
380
381  i4_time_class now;
382  while (active_list)
383    end_actives(active_list->key, now);
384
385  int i;
386  for (i=0; i<I4_NUM_KEYS; i++)
387  {
388    while (keys[i])
389    {
390      key_item *ki=keys[i];
391      keys[i]=keys[i]->next;
392      delete ki;
393    }
394  }
395
396  delete command_list;  command_list=0;
397  delete context_list;  context_list=0;
398  delete char_heap;     char_heap=0;
399
400  i4_kernel.unrequest_events(this,
401                             i4_device_class::FLAG_KEY_PRESS | i4_device_class::FLAG_KEY_RELEASE);
402}
403
404char *i4_key_man_class::alloc_str(char *s)
405{
406  int l=strlen(s)+1;
407  char *t=(char *)char_heap->malloc(l,"");
408  memcpy(t,s,l);
409  return t;
410}
411
412void i4_key_man_class::check_init()
413{
414  if (!context_list)
415  {
416    context_list = new i4_array<context>(32,32);
417    command_list = new i4_array<char *>(32,32);
418    char_heap = new i4_grow_heap_class(2048, 2048);
419
420    i4_kernel.request_events(this,
421                             i4_device_class::FLAG_KEY_PRESS | i4_device_class::FLAG_KEY_RELEASE);
422  }
423}
424
425int i4_key_man_class::get_context_id(char *context_name)
426{
427  check_init();
428  int s=context_list->size();
429  for (int i=0; i<s; i++)
430    if (strcmp( (*context_list)[i].name, context_name)==0)
431      return i;
432
433  if (context_list->size()==32)
434    i4_error("max contexts exceed with %s", context_name);
435
436  context *c=context_list->add();
437  c->name=alloc_str(context_name);
438  c->modifiers_taken=0;
439  c->modifiers_used=0;
440
441  return s;
442}
443
444int i4_key_man_class::get_command_id(char *command)
445{
446  check_init();
447  int s=command_list->size();
448  for (int i=0; i<s; i++)
449    if (strcmp( (*command_list)[i], command)==0)
450      return i;
451
452  command_list->add(alloc_str(command));
453  return s;
454}
455
456
457i4_bool i4_key_man_class::get_key_for_command(int command_id, i4_key &key, w16 &mod)
458{
459  for (int i=0; i<I4_NUM_KEYS; i++)
460  {
461    for (key_item *k=keys[i]; k; k=k->next)
462    {
463      if ((k->context_mask & (1<<context_id)) && (k->command_id == command_id))
464      {
465        key=i;
466        mod=k->modifier_flags;
467        return i4_T;
468      }
469    }
470  }
471
472  return i4_F;
473}
474
475
476
477void i4_key_matchup_class::add(char *command, int remap)   
478{
479  matchup.insert(new command_matchup(i4_key_man.get_command_id(command), remap));
480}
481
482int i4_key_matchup_class::remap(int command_id)
483{
484  command_matchup f=command_matchup(command_id,0);
485  command_matchup *m=matchup.find(&f);
486  if (m)
487    return m->remap_id;
488  else return -1;
489}
Note: See TracBrowser for help on using the repository browser.