installed pty
[VSoRC/.git] / node_modules / node-pty / deps / winpty / src / agent / DefaultInputMap.cc
1 // Copyright (c) 2015 Ryan Prichard
2 //
3 // Permission is hereby granted, free of charge, to any person obtaining a copy
4 // of this software and associated documentation files (the "Software"), to
5 // deal in the Software without restriction, including without limitation the
6 // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
7 // sell copies of the Software, and to permit persons to whom the Software is
8 // furnished to do so, subject to the following conditions:
9 //
10 // The above copyright notice and this permission notice shall be included in
11 // all copies or substantial portions of the Software.
12 //
13 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
18 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
19 // IN THE SOFTWARE.
20
21 #include "DefaultInputMap.h"
22
23 #include <windows.h>
24 #include <string.h>
25
26 #include <algorithm>
27
28 #include "../shared/StringBuilder.h"
29 #include "../shared/WinptyAssert.h"
30 #include "InputMap.h"
31
32 #define ESC "\x1B"
33 #define DIM(x) (sizeof(x) / sizeof((x)[0]))
34
35 namespace {
36
37 struct EscapeEncoding {
38     bool alt_prefix_allowed;
39     char prefix;
40     char id;
41     int modifiers;
42     InputMap::Key key;
43 };
44
45 // Modifiers.  A "modifier" is an integer from 2 to 8 that conveys the status
46 // of Shift(1), Alt(2), and Ctrl(4).  The value is constructed by OR'ing the
47 // appropriate value for each active modifier, then adding 1.
48 //
49 // Details:
50 //  - kBare:    expands to: ESC <prefix> <suffix>
51 //  - kSemiMod: expands to: ESC <prefix> <numid> ; <mod> <suffix>
52 //  - kBareMod: expands to: ESC <prefix> <mod> <suffix>
53 const int kBare        = 0x01;
54 const int kSemiMod     = 0x02;
55 const int kBareMod     = 0x04;
56
57 // Numeric escape sequences suffixes:
58 //  - with no flag: accept: ~
59 //  - kSuffixCtrl:  accept: ~ ^
60 //  - kSuffixShift: accept: ~ $
61 //  - kSuffixBoth:  accept: ~ ^ $ @
62 const int kSuffixCtrl  = 0x08;
63 const int kSuffixShift = 0x10;
64 const int kSuffixBoth  = kSuffixCtrl | kSuffixShift;
65
66 static const EscapeEncoding escapeLetterEncodings[] = {
67     // Conventional arrow keys
68     // kBareMod: Ubuntu /etc/inputrc and IntelliJ/JediTerm use escapes like: ESC [ n ABCD
69     { true,  '[', 'A', kBare | kBareMod | kSemiMod, { VK_UP,      '\0', 0             } },
70     { true,  '[', 'B', kBare | kBareMod | kSemiMod, { VK_DOWN,    '\0', 0             } },
71     { true,  '[', 'C', kBare | kBareMod | kSemiMod, { VK_RIGHT,   '\0', 0             } },
72     { true,  '[', 'D', kBare | kBareMod | kSemiMod, { VK_LEFT,    '\0', 0             } },
73
74     // putty.  putty uses this sequence for Ctrl-Arrow, Shift-Arrow, and
75     // Ctrl-Shift-Arrow, but I can only decode to one choice, so I'm just
76     // leaving the modifier off altogether.
77     { true,  'O', 'A', kBare,                       { VK_UP,      '\0', 0             } },
78     { true,  'O', 'B', kBare,                       { VK_DOWN,    '\0', 0             } },
79     { true,  'O', 'C', kBare,                       { VK_RIGHT,   '\0', 0             } },
80     { true,  'O', 'D', kBare,                       { VK_LEFT,    '\0', 0             } },
81
82     // rxvt, rxvt-unicode
83     // Shift-Ctrl-Arrow can't be identified.  It's the same as Shift-Arrow.
84     { true,  '[', 'a', kBare,                       { VK_UP,      '\0', SHIFT_PRESSED       } },
85     { true,  '[', 'b', kBare,                       { VK_DOWN,    '\0', SHIFT_PRESSED       } },
86     { true,  '[', 'c', kBare,                       { VK_RIGHT,   '\0', SHIFT_PRESSED       } },
87     { true,  '[', 'd', kBare,                       { VK_LEFT,    '\0', SHIFT_PRESSED       } },
88     { true,  'O', 'a', kBare,                       { VK_UP,      '\0', LEFT_CTRL_PRESSED   } },
89     { true,  'O', 'b', kBare,                       { VK_DOWN,    '\0', LEFT_CTRL_PRESSED   } },
90     { true,  'O', 'c', kBare,                       { VK_RIGHT,   '\0', LEFT_CTRL_PRESSED   } },
91     { true,  'O', 'd', kBare,                       { VK_LEFT,    '\0', LEFT_CTRL_PRESSED   } },
92
93     // Numpad 5 with NumLock off
94     //  * xterm, mintty, and gnome-terminal use `ESC [ E`.
95     //  * putty, TERM=cygwin, TERM=linux all use `ESC [ G` for 5
96     //  * putty uses `ESC O G` for Ctrl-5 and Shift-5.  Omit the modifier
97     //    as with putty's arrow keys.
98     //  * I never saw modifiers inserted into these escapes, but I think
99     //    it should be completely OK with the CSI escapes.
100     { true,  '[', 'E', kBare | kSemiMod,            { VK_CLEAR,   '\0', 0             } },
101     { true,  '[', 'G', kBare | kSemiMod,            { VK_CLEAR,   '\0', 0             } },
102     { true,  'O', 'G', kBare,                       { VK_CLEAR,   '\0', 0             } },
103
104     // Home/End, letter version
105     //  * gnome-terminal uses `ESC O [HF]`.  I never saw it modified.
106     // kBareMod: IntelliJ/JediTerm uses escapes like: ESC [ n HF
107     { true,  '[', 'H', kBare | kBareMod | kSemiMod, { VK_HOME,    '\0', 0             } },
108     { true,  '[', 'F', kBare | kBareMod | kSemiMod, { VK_END,     '\0', 0             } },
109     { true,  'O', 'H', kBare,                       { VK_HOME,    '\0', 0             } },
110     { true,  'O', 'F', kBare,                       { VK_END,     '\0', 0             } },
111
112     // F1-F4, letter version (xterm, VTE, konsole)
113     { true,  '[', 'P', kSemiMod,                    { VK_F1,      '\0', 0             } },
114     { true,  '[', 'Q', kSemiMod,                    { VK_F2,      '\0', 0             } },
115     { true,  '[', 'R', kSemiMod,                    { VK_F3,      '\0', 0             } },
116     { true,  '[', 'S', kSemiMod,                    { VK_F4,      '\0', 0             } },
117
118     // GNOME VTE and Konsole have special encodings for modified F1-F4:
119     //  * [VTE]     ESC O 1 ; n [PQRS]
120     //  * [Konsole] ESC O     n [PQRS]
121     { false, 'O', 'P', kBare | kBareMod | kSemiMod, { VK_F1,      '\0', 0             } },
122     { false, 'O', 'Q', kBare | kBareMod | kSemiMod, { VK_F2,      '\0', 0             } },
123     { false, 'O', 'R', kBare | kBareMod | kSemiMod, { VK_F3,      '\0', 0             } },
124     { false, 'O', 'S', kBare | kBareMod | kSemiMod, { VK_F4,      '\0', 0             } },
125
126     // Handle the "application numpad" escape sequences.
127     //
128     // Terminals output these codes under various circumstances:
129     //  * rxvt-unicode: numpad, hold down SHIFT
130     //  * rxvt: numpad, by default
131     //  * xterm: numpad, after enabling app-mode using DECPAM (`ESC =`).  xterm
132     //    generates `ESC O <mod> <letter>` for modified numpad presses,
133     //    necessitating kBareMod.
134     //  * mintty: by combining Ctrl with various keys such as '1' or ','.
135     //    Handling those keys is difficult, because mintty is generating the
136     //    same sequence for Ctrl-1 and Ctrl-NumPadEnd -- should the virtualKey
137     //    be '1' or VK_HOME?
138
139     { true,  'O', 'M', kBare | kBareMod,            { VK_RETURN,   '\r',   0 } },
140     { true,  'O', 'j', kBare | kBareMod,            { VK_MULTIPLY, '*',    0 } },
141     { true,  'O', 'k', kBare | kBareMod,            { VK_ADD,      '+',    0 } },
142     { true,  'O', 'm', kBare | kBareMod,            { VK_SUBTRACT, '-',    0 } },
143     { true,  'O', 'n', kBare | kBareMod,            { VK_DELETE,   '\0',   0 } },
144     { true,  'O', 'o', kBare | kBareMod,            { VK_DIVIDE,   '/',    0 } },
145     { true,  'O', 'p', kBare | kBareMod,            { VK_INSERT,   '\0',   0 } },
146     { true,  'O', 'q', kBare | kBareMod,            { VK_END,      '\0',   0 } },
147     { true,  'O', 'r', kBare | kBareMod,            { VK_DOWN,     '\0',   0 } },
148     { true,  'O', 's', kBare | kBareMod,            { VK_NEXT,     '\0',   0 } },
149     { true,  'O', 't', kBare | kBareMod,            { VK_LEFT,     '\0',   0 } },
150     { true,  'O', 'u', kBare | kBareMod,            { VK_CLEAR,    '\0',   0 } },
151     { true,  'O', 'v', kBare | kBareMod,            { VK_RIGHT,    '\0',   0 } },
152     { true,  'O', 'w', kBare | kBareMod,            { VK_HOME,     '\0',   0 } },
153     { true,  'O', 'x', kBare | kBareMod,            { VK_UP,       '\0',   0 } },
154     { true,  'O', 'y', kBare | kBareMod,            { VK_PRIOR,    '\0',   0 } },
155
156     { true,  '[', 'M', kBare | kSemiMod,            { VK_RETURN,   '\r',   0 } },
157     { true,  '[', 'j', kBare | kSemiMod,            { VK_MULTIPLY, '*',    0 } },
158     { true,  '[', 'k', kBare | kSemiMod,            { VK_ADD,      '+',    0 } },
159     { true,  '[', 'm', kBare | kSemiMod,            { VK_SUBTRACT, '-',    0 } },
160     { true,  '[', 'n', kBare | kSemiMod,            { VK_DELETE,   '\0',   0 } },
161     { true,  '[', 'o', kBare | kSemiMod,            { VK_DIVIDE,   '/',    0 } },
162     { true,  '[', 'p', kBare | kSemiMod,            { VK_INSERT,   '\0',   0 } },
163     { true,  '[', 'q', kBare | kSemiMod,            { VK_END,      '\0',   0 } },
164     { true,  '[', 'r', kBare | kSemiMod,            { VK_DOWN,     '\0',   0 } },
165     { true,  '[', 's', kBare | kSemiMod,            { VK_NEXT,     '\0',   0 } },
166     { true,  '[', 't', kBare | kSemiMod,            { VK_LEFT,     '\0',   0 } },
167     { true,  '[', 'u', kBare | kSemiMod,            { VK_CLEAR,    '\0',   0 } },
168     { true,  '[', 'v', kBare | kSemiMod,            { VK_RIGHT,    '\0',   0 } },
169     { true,  '[', 'w', kBare | kSemiMod,            { VK_HOME,     '\0',   0 } },
170     { true,  '[', 'x', kBare | kSemiMod,            { VK_UP,       '\0',   0 } },
171     { true,  '[', 'y', kBare | kSemiMod,            { VK_PRIOR,    '\0',   0 } },
172
173     { false, '[', 'Z', kBare,                       { VK_TAB,     '\t', SHIFT_PRESSED } },
174 };
175
176 static const EscapeEncoding escapeNumericEncodings[] = {
177     { true,  '[',  1,  kBare | kSemiMod | kSuffixBoth,      { VK_HOME,    '\0', 0             } },
178     { true,  '[',  2,  kBare | kSemiMod | kSuffixBoth,      { VK_INSERT,  '\0', 0             } },
179     { true,  '[',  3,  kBare | kSemiMod | kSuffixBoth,      { VK_DELETE,  '\0', 0             } },
180     { true,  '[',  4,  kBare | kSemiMod | kSuffixBoth,      { VK_END,     '\0', 0             } },
181     { true,  '[',  5,  kBare | kSemiMod | kSuffixBoth,      { VK_PRIOR,   '\0', 0             } },
182     { true,  '[',  6,  kBare | kSemiMod | kSuffixBoth,      { VK_NEXT,    '\0', 0             } },
183     { true,  '[',  7,  kBare | kSemiMod | kSuffixBoth,      { VK_HOME,    '\0', 0             } },
184     { true,  '[',  8,  kBare | kSemiMod | kSuffixBoth,      { VK_END,     '\0', 0             } },
185     { true,  '[', 11,  kBare | kSemiMod | kSuffixBoth,      { VK_F1,      '\0', 0             } },
186     { true,  '[', 12,  kBare | kSemiMod | kSuffixBoth,      { VK_F2,      '\0', 0             } },
187     { true,  '[', 13,  kBare | kSemiMod | kSuffixBoth,      { VK_F3,      '\0', 0             } },
188     { true,  '[', 14,  kBare | kSemiMod | kSuffixBoth,      { VK_F4,      '\0', 0             } },
189     { true,  '[', 15,  kBare | kSemiMod | kSuffixBoth,      { VK_F5,      '\0', 0             } },
190     { true,  '[', 17,  kBare | kSemiMod | kSuffixBoth,      { VK_F6,      '\0', 0             } },
191     { true,  '[', 18,  kBare | kSemiMod | kSuffixBoth,      { VK_F7,      '\0', 0             } },
192     { true,  '[', 19,  kBare | kSemiMod | kSuffixBoth,      { VK_F8,      '\0', 0             } },
193     { true,  '[', 20,  kBare | kSemiMod | kSuffixBoth,      { VK_F9,      '\0', 0             } },
194     { true,  '[', 21,  kBare | kSemiMod | kSuffixBoth,      { VK_F10,     '\0', 0             } },
195     { true,  '[', 23,  kBare | kSemiMod | kSuffixBoth,      { VK_F11,     '\0', 0             } },
196     { true,  '[', 24,  kBare | kSemiMod | kSuffixBoth,      { VK_F12,     '\0', 0             } },
197     { true,  '[', 25,  kBare | kSemiMod | kSuffixBoth,      { VK_F3,      '\0', SHIFT_PRESSED } },
198     { true,  '[', 26,  kBare | kSemiMod | kSuffixBoth,      { VK_F4,      '\0', SHIFT_PRESSED } },
199     { true,  '[', 28,  kBare | kSemiMod | kSuffixBoth,      { VK_F5,      '\0', SHIFT_PRESSED } },
200     { true,  '[', 29,  kBare | kSemiMod | kSuffixBoth,      { VK_F6,      '\0', SHIFT_PRESSED } },
201     { true,  '[', 31,  kBare | kSemiMod | kSuffixBoth,      { VK_F7,      '\0', SHIFT_PRESSED } },
202     { true,  '[', 32,  kBare | kSemiMod | kSuffixBoth,      { VK_F8,      '\0', SHIFT_PRESSED } },
203     { true,  '[', 33,  kBare | kSemiMod | kSuffixBoth,      { VK_F9,      '\0', SHIFT_PRESSED } },
204     { true,  '[', 34,  kBare | kSemiMod | kSuffixBoth,      { VK_F10,     '\0', SHIFT_PRESSED } },
205 };
206
207 const int kCsiShiftModifier = 1;
208 const int kCsiAltModifier   = 2;
209 const int kCsiCtrlModifier  = 4;
210
211 static inline bool useEnhancedForVirtualKey(uint16_t vk) {
212     switch (vk) {
213         case VK_UP:
214         case VK_DOWN:
215         case VK_LEFT:
216         case VK_RIGHT:
217         case VK_INSERT:
218         case VK_DELETE:
219         case VK_HOME:
220         case VK_END:
221         case VK_PRIOR:
222         case VK_NEXT:
223             return true;
224         default:
225             return false;
226     }
227 }
228
229 static void addSimpleEntries(InputMap &inputMap) {
230     struct SimpleEncoding {
231         const char *encoding;
232         InputMap::Key key;
233     };
234
235     static const SimpleEncoding simpleEncodings[] = {
236         // Ctrl-<letter/digit> seems to be handled OK by the default code path.
237
238         {   "\x7F",         { VK_BACK,  '\x08', 0,                                  } },
239         {   ESC "\x7F",     { VK_BACK,  '\x08', LEFT_ALT_PRESSED,                   } },
240         {   "\x03",         { 'C',      '\x03', LEFT_CTRL_PRESSED,                  } },
241
242         // Handle special F1-F5 for TERM=linux and TERM=cygwin.
243         {   ESC "[[A",      { VK_F1,    '\0',   0                                   } },
244         {   ESC "[[B",      { VK_F2,    '\0',   0                                   } },
245         {   ESC "[[C",      { VK_F3,    '\0',   0                                   } },
246         {   ESC "[[D",      { VK_F4,    '\0',   0                                   } },
247         {   ESC "[[E",      { VK_F5,    '\0',   0                                   } },
248
249         {   ESC ESC "[[A",  { VK_F1,    '\0',   LEFT_ALT_PRESSED                    } },
250         {   ESC ESC "[[B",  { VK_F2,    '\0',   LEFT_ALT_PRESSED                    } },
251         {   ESC ESC "[[C",  { VK_F3,    '\0',   LEFT_ALT_PRESSED                    } },
252         {   ESC ESC "[[D",  { VK_F4,    '\0',   LEFT_ALT_PRESSED                    } },
253         {   ESC ESC "[[E",  { VK_F5,    '\0',   LEFT_ALT_PRESSED                    } },
254     };
255
256     for (size_t i = 0; i < DIM(simpleEncodings); ++i) {
257         auto k = simpleEncodings[i].key;
258         if (useEnhancedForVirtualKey(k.virtualKey)) {
259             k.keyState |= ENHANCED_KEY;
260         }
261         inputMap.set(simpleEncodings[i].encoding,
262                      strlen(simpleEncodings[i].encoding),
263                      k);
264     }
265 }
266
267 struct ExpandContext {
268     InputMap &inputMap;
269     const EscapeEncoding &e;
270     char *buffer;
271     char *bufferEnd;
272 };
273
274 static inline void setEncoding(const ExpandContext &ctx, char *end,
275                                uint16_t extraKeyState) {
276     InputMap::Key k = ctx.e.key;
277     k.keyState |= extraKeyState;
278     if (k.keyState & LEFT_CTRL_PRESSED) {
279         switch (k.virtualKey) {
280             case VK_ADD:
281             case VK_DIVIDE:
282             case VK_MULTIPLY:
283             case VK_SUBTRACT:
284                 k.unicodeChar = '\0';
285                 break;
286             case VK_RETURN:
287                 k.unicodeChar = '\n';
288                 break;
289         }
290     }
291     if (useEnhancedForVirtualKey(k.virtualKey)) {
292         k.keyState |= ENHANCED_KEY;
293     }
294     ctx.inputMap.set(ctx.buffer, end - ctx.buffer, k);
295 }
296
297 static inline uint16_t keyStateForMod(int mod) {
298     int ret = 0;
299     if ((mod - 1) & kCsiShiftModifier)  ret |= SHIFT_PRESSED;
300     if ((mod - 1) & kCsiAltModifier)    ret |= LEFT_ALT_PRESSED;
301     if ((mod - 1) & kCsiCtrlModifier)   ret |= LEFT_CTRL_PRESSED;
302     return ret;
303 }
304
305 static void expandNumericEncodingSuffix(const ExpandContext &ctx, char *p,
306         uint16_t extraKeyState) {
307     ASSERT(p <= ctx.bufferEnd - 1);
308     {
309         char *q = p;
310         *q++ = '~';
311         setEncoding(ctx, q, extraKeyState);
312     }
313     if (ctx.e.modifiers & kSuffixShift) {
314         char *q = p;
315         *q++ = '$';
316         setEncoding(ctx, q, extraKeyState | SHIFT_PRESSED);
317     }
318     if (ctx.e.modifiers & kSuffixCtrl) {
319         char *q = p;
320         *q++ = '^';
321         setEncoding(ctx, q, extraKeyState | LEFT_CTRL_PRESSED);
322     }
323     if (ctx.e.modifiers & (kSuffixCtrl | kSuffixShift)) {
324         char *q = p;
325         *q++ = '@';
326         setEncoding(ctx, q, extraKeyState | SHIFT_PRESSED | LEFT_CTRL_PRESSED);
327     }
328 }
329
330 template <bool is_numeric>
331 static inline void expandEncodingAfterAltPrefix(
332         const ExpandContext &ctx, char *p, uint16_t extraKeyState) {
333     auto appendId = [&](char *&ptr) {
334         const auto idstr = decOfInt(ctx.e.id);
335         ASSERT(ptr <= ctx.bufferEnd - idstr.size());
336         std::copy(idstr.data(), idstr.data() + idstr.size(), ptr);
337         ptr += idstr.size();
338     };
339     ASSERT(p <= ctx.bufferEnd - 2);
340     *p++ = '\x1b';
341     *p++ = ctx.e.prefix;
342     if (ctx.e.modifiers & kBare) {
343         char *q = p;
344         if (is_numeric) {
345             appendId(q);
346             expandNumericEncodingSuffix(ctx, q, extraKeyState);
347         } else {
348             ASSERT(q <= ctx.bufferEnd - 1);
349             *q++ = ctx.e.id;
350             setEncoding(ctx, q, extraKeyState);
351         }
352     }
353     if (ctx.e.modifiers & kBareMod) {
354         ASSERT(!is_numeric && "kBareMod is invalid with numeric sequences");
355         for (int mod = 2; mod <= 8; ++mod) {
356             char *q = p;
357             ASSERT(q <= ctx.bufferEnd - 2);
358             *q++ = '0' + mod;
359             *q++ = ctx.e.id;
360             setEncoding(ctx, q, extraKeyState | keyStateForMod(mod));
361         }
362     }
363     if (ctx.e.modifiers & kSemiMod) {
364         for (int mod = 2; mod <= 8; ++mod) {
365             char *q = p;
366             if (is_numeric) {
367                 appendId(q);
368                 ASSERT(q <= ctx.bufferEnd - 2);
369                 *q++ = ';';
370                 *q++ = '0' + mod;
371                 expandNumericEncodingSuffix(
372                     ctx, q, extraKeyState | keyStateForMod(mod));
373             } else {
374                 ASSERT(q <= ctx.bufferEnd - 4);
375                 *q++ = '1';
376                 *q++ = ';';
377                 *q++ = '0' + mod;
378                 *q++ = ctx.e.id;
379                 setEncoding(ctx, q, extraKeyState | keyStateForMod(mod));
380             }
381         }
382     }
383 }
384
385 template <bool is_numeric>
386 static inline void expandEncoding(const ExpandContext &ctx) {
387     if (ctx.e.alt_prefix_allowed) {
388         // For better or for worse, this code expands all of:
389         //  *     ESC [       <key>     -- <key>
390         //  * ESC ESC [       <key>     -- Alt-<key>
391         //  *     ESC [ 1 ; 3 <key>     -- Alt-<key>
392         //  * ESC ESC [ 1 ; 3 <key>     -- Alt-<key> specified twice
393         // I suspect no terminal actually emits the last one (i.e. specifying
394         // the Alt modifier using both methods), but I have seen a terminal
395         // that emitted a prefix ESC for Alt and a non-Alt modifier.
396         char *p = ctx.buffer;
397         ASSERT(p <= ctx.bufferEnd - 1);
398         *p++ = '\x1b';
399         expandEncodingAfterAltPrefix<is_numeric>(ctx, p, LEFT_ALT_PRESSED);
400     }
401     expandEncodingAfterAltPrefix<is_numeric>(ctx, ctx.buffer, 0);
402 }
403
404 template <bool is_numeric, size_t N>
405 static void addEscapes(InputMap &inputMap, const EscapeEncoding (&encodings)[N]) {
406     char buffer[32];
407     for (size_t i = 0; i < DIM(encodings); ++i) {
408         ExpandContext ctx = {
409             inputMap, encodings[i],
410             buffer, buffer + sizeof(buffer)
411         };
412         expandEncoding<is_numeric>(ctx);
413     }
414 }
415
416 } // anonymous namespace
417
418 void addDefaultEntriesToInputMap(InputMap &inputMap) {
419     addEscapes<false>(inputMap, escapeLetterEncodings);
420     addEscapes<true>(inputMap, escapeNumericEncodings);
421     addSimpleEntries(inputMap);
422 }