Dillo v3.2.0-88-g47ab7c70
Loading...
Searching...
No Matches
keys.cc
Go to the documentation of this file.
1/*
2 * Key parser
3 *
4 * Copyright (C) 2009 Jorge Arellano Cid <jcid@dillo.org>
5 * Copyright (C) 2024-2025 Rodrigo Arias Mallo <rodarima@gmail.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 3 of the License, or
10 * (at your option) any later version.
11 */
12
13#include <FL/Fl.H>
14#include <stdio.h>
15#include <stdlib.h> /* strtol */
16#include <string.h>
17#include <ctype.h>
18
19#include "dlib/dlib.h"
20#include "keys.hh"
21#include "utf8.hh"
22#include "msg.h"
23#include "cache.h"
24#include "misc.h"
25
26/*
27 * Local data types
28 */
29typedef struct {
30 const char *name;
31 KeysCommand_t cmd;
32 int modifier, key;
33} KeyBinding_t;
34
35typedef struct {
36 const char *name;
37 const int value;
38} Mapping_t;
39
40
41/*
42 * Local data
43 */
44static const Mapping_t keyNames[] = {
45 { "Backspace", FL_BackSpace },
46 { "Delete", FL_Delete },
47 { "Down", FL_Down },
48 { "End", FL_End },
49 { "Esc", FL_Escape },
50 { "F1", FL_F + 1 },
51 { "F2", FL_F + 2 },
52 { "F3", FL_F + 3 },
53 { "F4", FL_F + 4 },
54 { "F5", FL_F + 5 },
55 { "F6", FL_F + 6 },
56 { "F7", FL_F + 7 },
57 { "F8", FL_F + 8 },
58 { "F9", FL_F + 9 },
59 { "F10", FL_F + 10 },
60 { "F11", FL_F + 11 },
61 { "F12", FL_F + 12 },
62 { "Home", FL_Home },
63 { "Insert", FL_Insert },
64 { "Left", FL_Left },
65 { "Menu", FL_Menu },
66 { "PageDown", FL_Page_Down },
67 { "PageUp", FL_Page_Up },
68 { "Print", FL_Print },
69 { "Return", FL_Enter },
70 { "Right", FL_Right },
71 { "Space", ' ' },
72 { "Tab", FL_Tab },
73 { "Up", FL_Up },
74 /* multimedia keys */
75 { "Back", FL_Back },
76 { "Favorites", FL_Favorites },
77 { "Forward", FL_Forward },
78 { "HomePage", FL_Home_Page },
79 { "Mail", FL_Mail },
80 { "MediaNext", FL_Media_Next },
81 { "MediaPlay", FL_Media_Play },
82 { "MediaPrev", FL_Media_Prev },
83 { "MediaStop", FL_Media_Stop },
84 { "Refresh", FL_Refresh },
85 { "Search", FL_Search },
86 { "Sleep", FL_Sleep },
87 { "Stop", FL_Stop },
88 { "VolumeDown", FL_Volume_Down },
89 { "VolumeMute", FL_Volume_Mute },
90 { "VolumeUp", FL_Volume_Up },
91};
92
93static const Mapping_t modifierNames[] = {
94 { "Shift", FL_SHIFT },
95 { "Ctrl", FL_CTRL },
96 { "Alt", FL_ALT },
97 { "Meta", FL_META },
98 { "Button1", FL_BUTTON1 },
99 { "Button2", FL_BUTTON2 },
100 { "Button3", FL_BUTTON3 }
101};
102
103static const KeyBinding_t default_keys[] = {
104 { "nop" , KEYS_NOP , 0 , 0 },
105 { "open" , KEYS_OPEN , FL_CTRL , 'o' },
106 { "new-window" , KEYS_NEW_WINDOW , FL_CTRL , 'n' },
107 { "new-tab" , KEYS_NEW_TAB , FL_CTRL , 't' },
108 { "left-tab" , KEYS_LEFT_TAB , FL_CTRL |
109 FL_SHIFT , FL_Tab },
110 { "left-tab" , KEYS_LEFT_TAB , FL_CTRL , FL_Page_Up },
111 { "right-tab" , KEYS_RIGHT_TAB , FL_CTRL , FL_Tab },
112 { "right-tab" , KEYS_RIGHT_TAB , FL_CTRL , FL_Page_Down },
113 { "close-tab" , KEYS_CLOSE_TAB , FL_CTRL , 'w' },
114 { "find" , KEYS_FIND , FL_CTRL , 'f' },
115 { "websearch" , KEYS_WEBSEARCH , FL_CTRL , 's' },
116 { "bookmarks" , KEYS_BOOKMARKS , FL_CTRL , 'b' },
117 { "reload" , KEYS_RELOAD , FL_CTRL , 'r' },
118 { "stop" , KEYS_STOP , 0 , 0 },
119 { "save" , KEYS_SAVE , 0 , 0 },
120 { "hide-panels" , KEYS_HIDE_PANELS , 0 , FL_Escape },
121 { "file-menu" , KEYS_FILE_MENU , FL_ALT , 'f' },
122 { "close-all" , KEYS_CLOSE_ALL , FL_CTRL , 'q' },
123 { "back" , KEYS_BACK , 0 , FL_BackSpace },
124 { "back" , KEYS_BACK , 0 , ',' },
125 { "forward" , KEYS_FORWARD , FL_SHIFT , FL_BackSpace },
126 { "forward" , KEYS_FORWARD , 0 , '.' },
127 { "goto" , KEYS_GOTO , FL_CTRL , 'l' },
128 { "home" , KEYS_HOME , FL_CTRL , 'h' },
129 { "view-source" , KEYS_VIEW_SOURCE , FL_CTRL , 'u' },
130 { "screen-up" , KEYS_SCREEN_UP , 0 , FL_Page_Up },
131 { "screen-up" , KEYS_SCREEN_UP , 0 , 'b' },
132 { "screen-down" , KEYS_SCREEN_DOWN , 0 , FL_Page_Down },
133 { "screen-down" , KEYS_SCREEN_DOWN , 0 , ' ' },
134 { "screen-left" , KEYS_SCREEN_LEFT , 0 , 0 },
135 { "screen-right" , KEYS_SCREEN_RIGHT , 0 , 0 },
136 { "line-up" , KEYS_LINE_UP , 0 , FL_Up },
137 { "line-down" , KEYS_LINE_DOWN , 0 , FL_Down },
138 { "left" , KEYS_LEFT , 0 , FL_Left },
139 { "right" , KEYS_RIGHT , 0 , FL_Right },
140 { "top" , KEYS_TOP , 0 , FL_Home },
141 { "bottom" , KEYS_BOTTOM , 0 , FL_End },
142 { "copy" , KEYS_COPY , FL_CTRL , 'c' },
143 { "zoom-in" , KEYS_ZOOM_IN , FL_CTRL , '+' },
144 { "zoom-in" , KEYS_ZOOM_IN , FL_CTRL , '=' /* US + */ },
145 { "zoom-out" , KEYS_ZOOM_OUT , FL_CTRL , '-' },
146 { "zoom-reset" , KEYS_ZOOM_RESET , FL_CTRL , '0' },
147 { "focus-tab1" , KEYS_FOCUS_TAB1 , FL_ALT , '1' },
148 { "focus-tab2" , KEYS_FOCUS_TAB2 , FL_ALT , '2' },
149 { "focus-tab3" , KEYS_FOCUS_TAB3 , FL_ALT , '3' },
150 { "focus-tab4" , KEYS_FOCUS_TAB4 , FL_ALT , '4' },
151 { "focus-tab5" , KEYS_FOCUS_TAB5 , FL_ALT , '5' },
152 { "focus-tab6" , KEYS_FOCUS_TAB6 , FL_ALT , '6' },
153 { "focus-tab7" , KEYS_FOCUS_TAB7 , FL_ALT , '7' },
154 { "focus-tab8" , KEYS_FOCUS_TAB8 , FL_ALT , '8' },
155 { "focus-tab9" , KEYS_FOCUS_TAB9 , FL_ALT , '9' },
156 { "focus-tab10" , KEYS_FOCUS_TAB10 , FL_ALT , '0' },
157};
158
160
161
162
167{
168 KeyBinding_t *node;
169
170 // Fill our key bindings list
171 bindings = dList_new(32);
172 for (uint_t i = 0; i < sizeof(default_keys) / sizeof(default_keys[0]); i++) {
173 if (default_keys[i].key) {
174 node = dNew(KeyBinding_t, 1);
175 node->name = dStrdup(default_keys[i].name);
176 node->cmd = default_keys[i].cmd;
177 node->modifier = default_keys[i].modifier;
178 node->key = default_keys[i].key;
180 }
181 }
182}
183
188{
189 KeyBinding_t *node;
190
191 while ((node = (KeyBinding_t*)dList_nth_data(bindings, 0))) {
192 dFree((char*)node->name);
194 dFree(node);
195 }
197}
198
202int Keys::nodeByKeyCmp(const void *node, const void *key)
203{
204 KeyBinding_t *n = (KeyBinding_t*)node, *k = (KeyBinding_t*)key;
205 _MSG("Keys::nodeByKeyCmp modifier=%d\n", k->modifier);
206 return (n->key != k->key) ? (n->key - k->key) : (n->modifier - k->modifier);
207}
208
214{
216 KeyBinding_t keyNode;
217
218 keyNode.modifier = Fl::event_state() & (FL_SHIFT | FL_CTRL |FL_ALT|FL_META);
219 if (iscntrl(Fl::event_text()[0])) {
220 keyNode.key = Fl::event_key();
221 } else {
222 const char *beyond = Fl::event_text() + Fl::event_length();
223 keyNode.key = a_Utf8_decode(Fl::event_text(), beyond, NULL);
224
225 /* BUG: The idea is to drop the modifiers if their use results in a
226 * different character (e.g., if shift-8 gives '*', drop the shift,
227 * but if ctrl-6 gives '6', keep the ctrl), but we have to compare a
228 * keysym with a Unicode codepoint, which only works for characters
229 * below U+0100 (those known to latin-1).
230 */
231 if (keyNode.key != Fl::event_key())
232 keyNode.modifier = 0;
233 }
234 _MSG("getKeyCmd: evkey=0x%x evtext=\'%s\' key=0x%x, mod=0x%x\n",
235 Fl::event_key(), Fl::event_text(), keyNode.key, keyNode.modifier);
236 void *data = dList_find_sorted(bindings, &keyNode, nodeByKeyCmp);
237 if (data)
238 ret = ((KeyBinding_t*)data)->cmd;
239 return ret;
240}
241
245void Keys::delKeyCmd(int key, int mod)
246{
247 KeyBinding_t keyNode, *node;
248 keyNode.key = key;
249 keyNode.modifier = mod;
250
251 node = (KeyBinding_t*) dList_find_sorted(bindings, &keyNode, nodeByKeyCmp);
252 if (node) {
253 dList_remove(bindings, node);
254 dFree((char*)node->name);
255 dFree(node);
256 }
257}
258
264int Keys::getKeyCode(char *keyName)
265{
266 uint_t i;
267 for (i = 0; i < sizeof(keyNames) / sizeof(keyNames[0]); i++) {
268 if (!dStrAsciiCasecmp(keyNames[i].name, keyName)) {
269 return keyNames[i].value;
270 }
271 }
272
273 return -1;
274}
275
276const char *Keys::getKeyName(int key)
277{
278 static char buf[128];
279
280 uint_t i;
281 for (i = 0; i < sizeof(keyNames) / sizeof(keyNames[0]); i++) {
282 if (keyNames[i].value == key)
283 return keyNames[i].name;
284 }
285
286 if (d_isascii(key)) {
287 sprintf(buf, "%c", key);
288 } else {
289 /* Otherwise print hexadecimal */
290 sprintf(buf, "0x%x", key);
291 }
292
293 return buf;
294}
295
300KeysCommand_t Keys::getCmdCode(const char *commandName)
301{
302 uint_t i;
303
304 for (i = 0; i < sizeof(default_keys) / sizeof(KeyBinding_t); i++) {
305 if (!dStrAsciiCasecmp(default_keys[i].name, commandName))
306 return default_keys[i].cmd;
307 }
308 return KEYS_INVALID;
309}
310
315int Keys::getModifier(char *modifierName)
316{
317 uint_t i;
318 for (i = 0; i < sizeof(modifierNames) / sizeof(modifierNames[0]); i++) {
319 if (!dStrAsciiCasecmp(modifierNames[i].name, modifierName)) {
320 return modifierNames[i].value;
321 }
322 }
323
324 return -1;
325}
326
332{
333 int len = dList_length(bindings);
334
335 for (int i = 0; i < len; i++) {
336 KeyBinding_t *node = (KeyBinding_t*)dList_nth_data(bindings, i);
337 if (cmd == node->cmd)
338 return node->modifier + node->key;
339 }
340 return 0;
341}
342
347void Keys::parseKey(char *key, char *commandName)
348{
349 char *p, *modstr, *keystr;
350 KeysCommand_t symcode;
351 int st, keymod = 0, keycode = 0;
352
353 _MSG("Keys::parseKey key='%s' commandName='%s'\n", key, commandName);
354
355 // Get command code
356 if ((symcode = getCmdCode(commandName)) == KEYS_INVALID) {
357 MSG("Keys::parseKey: Invalid command name: '%s'\n", commandName);
358 return;
359 }
360
361 // Skip space
362 for ( ; isspace(*key); ++key) ;
363 // Get modifiers
364 while(*key == '<' && (p = strchr(key, '>'))) {
365 ++key;
366 modstr = dStrndup(key, p - key);
367 if ((st = getModifier(modstr)) == -1) {
368 MSG("Keys::parseKey unknown modifier: %s\n", modstr);
369 } else {
370 keymod |= st;
371 }
372 dFree(modstr);
373 key = p + 1;
374 }
375 // Allow trailing space after keyname
376 keystr = (*key && (p = strchr(key + 1, ' '))) ? dStrndup(key, p - key - 1) :
377 dStrdup(key);
378 // Get key code
379 if (!key[1]) {
380 keycode = *key;
381 } else if (a_Utf8_char_count(keystr, strlen(keystr)) == 1) {
382 const char *beyond = keystr + strlen(keystr);
383 keycode = a_Utf8_decode(keystr, beyond, NULL);
384 } else if (key[0] == '0' && key[1] == 'x') {
385 /* keysym */
386 keycode = strtol(key, NULL, 0x10);
387 } else if ((st = getKeyCode(keystr)) == -1) {
388 MSG("Keys::parseKey unknown keyname: %s\n", keystr);
389 } else {
390 keycode = st;
391 }
392 dFree(keystr);
393
394 // Set binding
395 if (keycode) {
396 delKeyCmd(keycode, keymod);
397 if (symcode != KEYS_NOP) {
398 KeyBinding_t *node = dNew(KeyBinding_t, 1);
399 node->name = dStrdup(commandName);
400 node->cmd = symcode;
401 node->modifier = keymod;
402 node->key = keycode;
404 _MSG("parseKey: Adding key=%d, mod=%d\n", node->key, node->modifier);
405 }
406 }
407}
408
412void Keys::parse(FILE *fp)
413{
414 char *line, *keycomb, *command;
415 int st, lineno = 1;
416
417 // scan the file line by line
418 while ((line = dGetline(fp)) != NULL) {
419 st = dParser_parse_rc_line(&line, &keycomb, &command);
420
421 if (st == 0) {
422 _MSG("Keys::parse: keycomb=%s, command=%s\n", keycomb, command);
423 parseKey(keycomb, command);
424 } else if (st < 0) {
425 MSG("Keys::parse: Syntax error in keysrc line %d: "
426 "keycomb=\"%s\" command=\"%s\"\n", lineno, keycomb, command);
427 }
428
429 dFree(line);
430 ++lineno;
431 }
432 fclose(fp);
433}
434
436{
437 int len = dList_length(bindings);
438 Dstr *table = dStr_new("");
439
440 dStr_sprintfa(table,
441 "<!DOCTYPE HTML>\n"
442 "<html>\n"
443 "<head>\n"
444 " <title>Keyboard shortcuts</title>\n"
445 " <style>\n"
446 " body {\n"
447 " background: white;\n"
448 " margin: 3em;\n"
449 " font-size: 16px;\n"
450 " font-family: sans-serif;\n"
451 " line-height: 1.4em;\n"
452 " }\n"
453 " .main { max-width: 40em; }\n"
454 " p { margin-top: 1em; }\n"
455 " table {\n"
456 " border-collapse: collapse;\n"
457 " }\n"
458 " th,td {\n"
459 " padding: 0.25em;\n"
460 " padding: 0.25em;\n"
461 " border-spacing: 0px;\n"
462 " border-top: solid 1px #ccc;\n"
463 " border-bottom: solid 1px #ccc;\n"
464 " }\n"
465 " td.key {\n"
466 " min-width: 15em;\n"
467 " }\n"
468 " td.action {\n"
469 " min-width: 10em;\n"
470 " }\n"
471 " th {\n"
472 " background-color: #eee;\n"
473 " }\n"
474 " kbd {\n"
475 " display: inline-block;\n"
476 " border: solid 1px #aaa;\n"
477 " padding: 1px 5px;\n"
478 " }\n"
479 " kbd.mod {\n"
480 " background: #f5f5f5;\n"
481 " }\n"
482 " </style>\n"
483 "</head>\n"
484 "<body>\n"
485 "<div class=\"main\">\n"
486 "\n"
487 "<h1>Keyboard shortcuts</h1>\n"
488 "\n"
489 "<p>The following table contains the current key bindings in Dillo.\n"
490 "To change them, edit the configuration file <code>~/.dillo/keysrc</code> \n"
491 "and restart the browser.</p>\n"
492 "<table>\n"
493 "<tr><th>Shortcut<th>Action</tr>\n");
494
495 for (int i = 0; i < len; i++) {
496 KeyBinding_t *node = (KeyBinding_t*)dList_nth_data(bindings, i);
497 const char *key = Keys::getKeyName(node->key);
498
499 dStr_sprintfa(table, "<tr><td class=key><code>");
500
501 for (uint_t j = 0; j < sizeof(modifierNames) / sizeof(modifierNames[0]); j++) {
502 if (modifierNames[j].value & node->modifier) {
503 dStr_sprintfa(table, "<kbd class=mod>%s</kbd> ",
504 modifierNames[j].name);
505 }
506 }
507
508 dStr_sprintfa(table, "<kbd class=key>%s</kbd></code></td>", key);
509 dStr_sprintfa(table, "<td class=action><code>%s</code></td>", node->name);
510 dStr_sprintfa(table, "</tr>\n");
511 }
512
513 dStr_sprintfa(table,
514 "</table>\n"
515 "</div>\n"
516 "</body>\n"
517 "</html>\n");
518
519 /* inject keymaps after loading them */
520 DilloUrl *url = a_Url_new("about:keys", NULL);
521 a_Cache_entry_inject(url, table);
522 dStr_free(table, 1);
523 a_Url_free(url);
524}
#define _MSG(...)
Definition bookmarks.c:45
#define MSG(...)
Definition bookmarks.c:46
void a_Cache_entry_inject(const DilloUrl *Url, Dstr *data_ds)
Inject full page content directly into the cache.
Definition cache.c:290
static void parse(FILE *fp)
Parse the keysrc.
Definition keys.cc:412
static void init()
Initialize the bindings list.
Definition keys.cc:166
static KeysCommand_t getKeyCmd(void)
Look if the just pressed key is bound to a command.
Definition keys.cc:213
static KeysCommand_t getCmdCode(const char *symbolName)
Takes a command name and searches it in the mapping table.
Definition keys.cc:300
static int getShortcut(KeysCommand_t cmd)
Given a keys command, return a shortcut for it, or 0 if there is none (e.g., for KEYS_NEW_WINDOW,...
Definition keys.cc:331
static void free()
Free data.
Definition keys.cc:187
static void delKeyCmd(int key, int mod)
Remove a key binding from the table.
Definition keys.cc:245
static const char * getKeyName(int key)
Definition keys.cc:276
static void parseKey(char *key, char *symbol)
Parse a key-combination/command-name pair, and insert it into the bindings list.
Definition keys.cc:347
static void genAboutKeys(void)
Definition keys.cc:435
static int nodeByKeyCmp(const void *node, const void *key)
Compare function by {key,modifier} pairs.
Definition keys.cc:202
static int getModifier(char *modifierName)
Takes a modifier name and looks it up in the mapping table.
Definition keys.cc:315
static int getKeyCode(char *keyName)
Takes a key name and looks it up in the mapping table.
Definition keys.cc:264
unsigned int uint_t
Definition d_size.h:20
char * dGetline(FILE *stream)
Get a line from a FILE stream.
Definition dlib.c:956
void dList_insert_sorted(Dlist *lp, void *data, dCompareFunc func)
Insert an element into a sorted list.
Definition dlib.c:797
void dFree(void *mem)
Definition dlib.c:68
int dStrAsciiCasecmp(const char *s1, const char *s2)
Definition dlib.c:203
void dStr_sprintfa(Dstr *ds, const char *format,...)
Printf-like function that appends.
Definition dlib.c:464
char * dStrdup(const char *s)
Definition dlib.c:77
Dlist * dList_new(int size)
Create a new empty list.
Definition dlib.c:576
int dList_length(Dlist *lp)
For completing the ADT.
Definition dlib.c:641
void * dList_nth_data(Dlist *lp, int n0)
Return the nth data item, NULL when not found or 'n0' is out of range.
Definition dlib.c:690
void dList_remove_fast(Dlist *lp, const void *data)
Remove a data item without preserving order.
Definition dlib.c:651
void dStr_free(Dstr *ds, int all)
Free a dillo string.
Definition dlib.c:337
char * dStrndup(const char *s, size_t sz)
Definition dlib.c:88
Dstr * dStr_new(const char *s)
Create a new string.
Definition dlib.c:325
void * dList_find_sorted(Dlist *lp, const void *data, dCompareFunc func)
Search a sorted list.
Definition dlib.c:824
void dList_free(Dlist *lp)
Free a list (not its elements)
Definition dlib.c:592
int dParser_parse_rc_line(char **line, char **name, char **value)
Take a dillo rc line and return 'name' and 'value' pointers to it.
Definition dlib.c:862
void dList_remove(Dlist *lp, const void *data)
Definition dlib.c:669
#define dNew(type, count)
Definition dlib.h:61
static const KeyBinding_t default_keys[]
Definition keys.cc:103
static const Mapping_t modifierNames[]
Definition keys.cc:93
static const Mapping_t keyNames[]
Definition keys.cc:44
static Dlist * bindings
Definition keys.cc:159
KeysCommand_t
Definition keys.hh:17
@ KEYS_INVALID
Definition keys.hh:18
@ KEYS_COPY
Definition keys.hh:52
@ KEYS_SCREEN_RIGHT
Definition keys.hh:45
@ KEYS_BOTTOM
Definition keys.hh:51
@ KEYS_STOP
Definition keys.hh:32
@ KEYS_LEFT
Definition keys.hh:48
@ KEYS_FOCUS_TAB10
Definition keys.hh:65
@ KEYS_RELOAD
Definition keys.hh:31
@ KEYS_RIGHT
Definition keys.hh:49
@ KEYS_NOP
Definition keys.hh:19
@ KEYS_FOCUS_TAB9
Definition keys.hh:64
@ KEYS_LEFT_TAB
Definition keys.hh:23
@ KEYS_FOCUS_TAB7
Definition keys.hh:62
@ KEYS_RIGHT_TAB
Definition keys.hh:24
@ KEYS_BOOKMARKS
Definition keys.hh:30
@ KEYS_CLOSE_ALL
Definition keys.hh:36
@ KEYS_BACK
Definition keys.hh:37
@ KEYS_ZOOM_OUT
Definition keys.hh:54
@ KEYS_FOCUS_TAB8
Definition keys.hh:63
@ KEYS_LINE_UP
Definition keys.hh:46
@ KEYS_FOCUS_TAB5
Definition keys.hh:60
@ KEYS_WEBSEARCH
Definition keys.hh:29
@ KEYS_ZOOM_RESET
Definition keys.hh:55
@ KEYS_SCREEN_DOWN
Definition keys.hh:43
@ KEYS_GOTO
Definition keys.hh:39
@ KEYS_OPEN
Definition keys.hh:20
@ KEYS_FOCUS_TAB4
Definition keys.hh:59
@ KEYS_SAVE
Definition keys.hh:33
@ KEYS_FIND
Definition keys.hh:28
@ KEYS_FOCUS_TAB2
Definition keys.hh:57
@ KEYS_HIDE_PANELS
Definition keys.hh:34
@ KEYS_FILE_MENU
Definition keys.hh:35
@ KEYS_FORWARD
Definition keys.hh:38
@ KEYS_FOCUS_TAB3
Definition keys.hh:58
@ KEYS_TOP
Definition keys.hh:50
@ KEYS_FOCUS_TAB6
Definition keys.hh:61
@ KEYS_VIEW_SOURCE
Definition keys.hh:41
@ KEYS_HOME
Definition keys.hh:40
@ KEYS_LINE_DOWN
Definition keys.hh:47
@ KEYS_NEW_WINDOW
Definition keys.hh:21
@ KEYS_FOCUS_TAB1
Definition keys.hh:56
@ KEYS_NEW_TAB
Definition keys.hh:22
@ KEYS_SCREEN_LEFT
Definition keys.hh:44
@ KEYS_SCREEN_UP
Definition keys.hh:42
@ KEYS_CLOSE_TAB
Definition keys.hh:25
@ KEYS_ZOOM_IN
Definition keys.hh:53
#define d_isascii(c)
Definition misc.h:12
Definition url.h:88
Definition dlib.h:144
Definition dlib.h:114
void a_Url_free(DilloUrl *url)
Free a DilloUrl.
Definition url.c:208
DilloUrl * a_Url_new(const char *url_str, const char *base_url)
Transform (and resolve) an URL string into the respective DilloURL.
Definition url.c:371
uint_t a_Utf8_decode(const char *str, const char *end, int *len)
Decode a single UTF-8-encoded character starting at p.
Definition utf8.cc:46
int a_Utf8_char_count(const char *str, int len)
Definition utf8.cc:104