|
1 # Copyright 2000-2004 Michael Hudson mwh@python.net |
|
2 # |
|
3 # All Rights Reserved |
|
4 # |
|
5 # Portions Copyright (c) 2005 Nokia Corporation |
|
6 # |
|
7 # Permission to use, copy, modify, and distribute this software and |
|
8 # its documentation for any purpose is hereby granted without fee, |
|
9 # provided that the above copyright notice appear in all copies and |
|
10 # that both that copyright notice and this permission notice appear in |
|
11 # supporting documentation. |
|
12 # |
|
13 # THE AUTHOR MICHAEL HUDSON DISCLAIMS ALL WARRANTIES WITH REGARD TO |
|
14 # THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY |
|
15 # AND FITNESS, IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, |
|
16 # INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER |
|
17 # RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF |
|
18 # CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN |
|
19 # CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
|
20 |
|
21 # (naming modules after builtin functions is not such a hot idea...) |
|
22 |
|
23 # an KeyTrans instance translates Event objects into Command objects |
|
24 |
|
25 # hmm, at what level do we want [C-i] and [tab] to be equivalent? |
|
26 # [meta-a] and [esc a]? obviously, these are going to be equivalent |
|
27 # for the UnixConsole, but should they be for PygameConsole? |
|
28 |
|
29 # it would in any situation seem to be a bad idea to bind, say, [tab] |
|
30 # and [C-i] to *different* things... but should binding one bind the |
|
31 # other? |
|
32 |
|
33 # executive, temporary decision: [tab] and [C-i] are distinct, but |
|
34 # [meta-key] is identified with [esc key]. We demand that any console |
|
35 # class does quite a lot towards emulating a unix terminal. |
|
36 |
|
37 try: |
|
38 import unicodedata |
|
39 except ImportError: |
|
40 import dumbunicodedata as unicodedata |
|
41 |
|
42 class InputTranslator(object): |
|
43 def push(self, evt): |
|
44 pass |
|
45 def get(self): |
|
46 pass |
|
47 def empty(self): |
|
48 pass |
|
49 |
|
50 class KeymapTranslator(InputTranslator): |
|
51 def __init__(self, keymap, verbose=0, |
|
52 invalid_cls=None, character_cls=None): |
|
53 self.verbose = verbose |
|
54 from pyrepl.keymap import compile_keymap, parse_keys |
|
55 self.keymap = keymap |
|
56 self.invalid_cls = invalid_cls |
|
57 self.character_cls = character_cls |
|
58 d = {} |
|
59 for keyspec, command in keymap: |
|
60 keyseq = tuple(parse_keys(keyspec)) |
|
61 d[keyseq] = command |
|
62 if self.verbose: |
|
63 print d |
|
64 self.k = self.ck = compile_keymap(d, ()) |
|
65 self.results = [] |
|
66 self.stack = [] |
|
67 def push(self, evt): |
|
68 if self.verbose: |
|
69 print "pushed", evt.data, |
|
70 key = evt.data |
|
71 d = self.k.get(key) |
|
72 if isinstance(d, dict): |
|
73 if self.verbose: |
|
74 print "transition" |
|
75 self.stack.append(key) |
|
76 self.k = d |
|
77 else: |
|
78 if d is None: |
|
79 if self.verbose: |
|
80 print "invalid" |
|
81 if self.stack or len(key) > 1 or (unicodedata.category(key) and unicodedata.category(key).startswith('C')): |
|
82 self.results.append( |
|
83 (self.invalid_cls, self.stack + [key])) |
|
84 else: |
|
85 # small optimization: |
|
86 self.k[key] = self.character_cls |
|
87 self.results.append( |
|
88 (self.character_cls, [key])) |
|
89 else: |
|
90 if self.verbose: |
|
91 print "matched", d |
|
92 self.results.append((d, self.stack + [key])) |
|
93 self.stack = [] |
|
94 self.k = self.ck |
|
95 def get(self): |
|
96 if self.results: |
|
97 return self.results.pop(0) |
|
98 else: |
|
99 return None |
|
100 def empty(self): |
|
101 return not self.results |