@@ 194,7 194,8 @@ int levenshtein_distance(const char *a, const char* b) {
 }
 
 int MAX_DIST = 3; // Is this ideal?
-char *select_link(char **links, char *command) {
+char **links = NULL;
+char *select_link(char *command) {
     // Pass 1, min distance
     int score = INT_MAX;
     for (int i = 0; strcmp(links[i], " ") != 0; i++) {
@@ 210,7 211,7 @@ char *select_link(char **links, char *command) {
 
     // Pass 3: Retrieve answer
     for (int i = 0; strcmp(links[i], " ") != 0; i += 3) {
-        if (command[0] != '\0') {// "" to read entire link table...
+        if (command[0] != '\0' || command[0] == '\n') {// "" to read entire link table...
             if (score < levenshtein_distance(command, links[i]) &&
                 score < levenshtein_distance(command, links[i+1]) &&
                 score < levenshtein_distance(command, links[i+2])) continue;
@@ 229,103 230,150 @@ char *select_link(char **links, char *command) {
 
 struct termios stored_settings, no_echo;
 int read_keyboard = 0;
-int speak_finalize(char *ssml, char **links, char **out_link) {
-    while (read_keyboard) {
-        if (out_link != NULL && *out_link != NULL) return 0;
-
-        if (getc(stdin) == '\033') {
-            char mark[200];
-            char fallback[200];
-            espeak_Cancel();
-            char c = getc(stdin);
-            if (c == 0 || c == -1 || c == '\033' || c == 'q') goto close; // skip [
-            switch (getc(stdin)) {
-            case 'A':
-                // 🠕
-                if (in_table) {
-                    tablerow--;
-                    if (tablerow > 0) {
-                        sprintf(mark, "-rhaps-tablecell%i:%ix%i", tableno, tablerow, tablecol);
-                        speak(ssml, mark, NULL);
-                        break;
-                    } else in_table = 0;
-                }
-                section_no--;
-                sprintf(mark, "-rhaps-section%i", section_no);
-                speak(ssml, section_no > 0 ? mark : NULL, NULL);
-                break;
-            case 'B':
-                // 🠗
-                if (in_table) {
-                    tablerow++;
+
+void read_page(char *uri, int read_input);
+gboolean read_stdin(GIOChannel *source, GIOCondition condition, gpointer data) {
+    char *ssml = data;
+
+    if (getc(stdin) == '\033') {
+        char mark[200];
+        char fallback[200];
+        espeak_Cancel();
+        char c = getc(stdin);
+        if (c == 0 || c == -1 || c == '\033' || c == 'q') return 1; // skip [
+        switch (getc(stdin)) {
+        case 'A':
+            // 🠕
+            if (in_table) {
+                tablerow--;
+                if (tablerow > 0) {
                     sprintf(mark, "-rhaps-tablecell%i:%ix%i", tableno, tablerow, tablecol);
-                    sprintf(fallback, "-rhaps-section%i", section_no+1);
-                    speak(ssml, mark, fallback);
-                    break; // FIXME What if that mark doesn't exist?
-                }
-                section_no++;
-                sprintf(mark, "-rhaps-section%i", section_no);
-                speak(ssml, section_no > 0 ? mark : NULL, NULL);
-                break;
-            case 'C':
-                // ➔
-                if (in_table) {
-                    tablecol++;
+                    speak(ssml, mark, NULL);
+                    break;
+                } else in_table = 0;
+            }
+            section_no--;
+            sprintf(mark, "-rhaps-section%i", section_no);
+            speak(ssml, section_no > 0 ? mark : NULL, NULL);
+            break;
+        case 'B':
+            // 🠗
+            if (in_table) {
+                tablerow++;
+                sprintf(mark, "-rhaps-tablecell%i:%ix%i", tableno, tablerow, tablecol);
+                sprintf(fallback, "-rhaps-section%i", section_no+1);
+                speak(ssml, mark, fallback);
+                break; // FIXME What if that mark doesn't exist?
+            }
+            section_no++;
+            sprintf(mark, "-rhaps-section%i", section_no);
+            speak(ssml, section_no > 0 ? mark : NULL, NULL);
+            break;
+        case 'C':
+            // ➔
+            if (in_table) {
+                tablecol++;
+                sprintf(mark, "-rhaps-tablecell%i:%ix%i", tableno, tablerow, tablecol);
+                sprintf(fallback, "-rhaps-paragraph%i", paragraph_no+1);
+                speak(ssml, mark, fallback);
+                break; // FIXME What if that mark doesn't exist?
+            }
+            paragraph_no++;
+            sprintf(mark, "-rhaps-paragraph%i", paragraph_no);
+            speak(ssml, paragraph_no > 0 ? mark : NULL, NULL);
+            break;
+        case 'D':
+            // 🠔
+            if (in_table) {
+                tablecol--;
+                if (tablecol > 0) {
                     sprintf(mark, "-rhaps-tablecell%i:%ix%i", tableno, tablerow, tablecol);
-                    sprintf(fallback, "-rhaps-paragraph%i", paragraph_no+1);
-                    speak(ssml, mark, fallback);
-                    break; // FIXME What if that mark doesn't exist?
-                }
-                paragraph_no++;
-                sprintf(mark, "-rhaps-paragraph%i", paragraph_no);
-                speak(ssml, paragraph_no > 0 ? mark : NULL, NULL);
-                break;
-            case 'D':
-                // 🠔
-                if (in_table) {
-                    tablecol--;
-                    if (tablecol > 0) {
-                        sprintf(mark, "-rhaps-tablecell%i:%ix%i", tableno, tablerow, tablecol);
-                        speak(ssml, mark, NULL);
-                        break;
-                    } else in_table = 0;
-                }
-                paragraph_no--;
-                sprintf(mark, "-rhaps-paragraph%i", paragraph_no);
-                speak(ssml, paragraph_no > 0 ? mark : NULL, NULL);
-                break;
+                    speak(ssml, mark, NULL);
+                    break;
+                } else in_table = 0;
             }
-        } else {
-            // Read in a line
-            tcsetattr(0, TCSANOW, &stored_settings);
-            char *line = NULL;
-            size_t len = 0;
-            if (getline(&line, &len, stdin) < 0)
-                fprintf(stderr, "Failed to read stdin line!\n");
-            else if (*line == '\n') {
-                espeak_Cancel();
-                return 0;
-            } else if (out_link != NULL)
-                *out_link = select_link(links, line);
-            tcsetattr(0, TCSANOW, &no_echo);
+            paragraph_no--;
+            sprintf(mark, "-rhaps-paragraph%i", paragraph_no);
+            speak(ssml, paragraph_no > 0 ? mark : NULL, NULL);
+            break;
+        }
+    } else {
+        // Read in a line, with full terminal emulator i18n.
+        tcsetattr(0, TCSANOW, &stored_settings);
+        char *line = NULL;
+        size_t len = 0;
+        if (getline(&line, &len, stdin) < 0) {
+            fprintf(stderr, "Failed to read stdin line!\n");
+            return TRUE;
         }
+        tcsetattr(0, TCSANOW, &no_echo);
+        read_page(select_link(line), 1);
+        return FALSE;
     }
-    espeak_ng_STATUS result = espeak_ng_Synchronize();
-    if (result != ENS_OK) {
-        espeak_ng_PrintStatusCodeMessage(result, stderr, context);
-        return 4;
+    return TRUE;
+}
+
+int speak_finalize(char *ssml) {
+    while (read_keyboard) {
+        if (!read_stdin(NULL, 0, ssml)) return 0;
     }
 
 close:
-    if (path_wav != NULL) sf_close(fd_wav);
-    espeak_ng_Terminate();
     return 0;
 }
 
 /* Main driver */
-void write_links(FILE *dest, char **links) {
+int speak_err = 0;
+struct session *session = NULL;
+struct page *referer = NULL;
+
+int use_espeak = 0;
+char *logpath = NULL;
+char *mimes = "text/html text/xml application/xml application/xhtml+xml text/plain";
+FILE *fd_ssml = NULL;
+FILE *fd_links = NULL;
+
+void write_links() {
     for (int i = 0; strcmp(links[i], " ") != 0; i++) {
-        fprintf(dest, "%s%c", links[i], (i % 3) == 2 ? '\n' : '\t');
+        fprintf(fd_links, "%s%c", links[i], (i % 3) == 2 ? '\n' : '\t');
+    }
+}
+
+void read_page(char *uri, int read_input) {
+    for (int i = 0; strcmp(links[i], " ") != 0; i++) free(links[i]);
+    free(links);
+
+    if (use_espeak && speak_err == 0) speak_text(uri, espeakRATE, 10);
+    #ifdef WITH_SPEECHD
+    else if (spd_conn != NULL) spd_say(spd_conn, SPD_MESSAGE, uri);
+    #endif
+    else printf("%s\n", uri);
+
+    struct page *page = c_fetchURL(session, mimes, referer, uri);
+    referer = page;
+    char *ssml = c_renderDoc(session, page, use_espeak);
+    links = c_extractLinks(page);
+
+    if (logpath != NULL) c_writeLog(logpath, session);
+
+    if (fd_ssml != NULL) fprintf(fd_ssml, "%s\n", ssml);
+    if (read_keyboard && strcmp(uri, "about:welcome")) select_link("");
+    if (fd_links != NULL) write_links(fd_links, links);
+    if (use_espeak & speak_err == 0) speak(ssml, "main", NULL);
+    #ifdef WITH_SPEECHD
+    if (spd_conn != NULL) spd_say(spd_conn, SPD_MESSAGE, ssml);
+    #endif
+
+    c_freePage(page);
+    free(uri);
+
+    if (read_input) {
+        g_io_add_watch(g_io_channel_unix_new(0), G_IO_IN|G_IO_HUP, read_stdin, ssml);
+        // if (use_espeak & speak_err == 0) speak_err = speak_finalize(ssml);
+    } else {
+        free(ssml);
+        for (int i = 0; strcmp(links[i], " ") != 0; i++) free(links[i]);
+        free(links);
     }
 }
 
@@ 340,16 388,10 @@ FILE *parse_opt_file() {
 }
 
 int main(int argc, char **argv) {
-    int speak_err = 0;
     hs_init(&argc, &argv);
     gst_init(&argc, &argv);
     GMainLoop *loop = g_main_loop_new(NULL, FALSE);
 
-    char *mimes = "text/html text/xml application/xml application/xhtml+xml text/plain";
-    char *logpath = NULL;
-    FILE *fd_ssml = NULL;
-    FILE *fd_links = NULL;
-    int use_espeak = 0;
     tcgetattr(0, &stored_settings);
     #ifdef WITH_SPEECHD
     SPDConnection *spd_conn = NULL;
@@ 462,53 504,30 @@ int main(int argc, char **argv) {
     if (dist != 3) return 11;
 #endif
 
-    struct session *session = c_newSession();
-    struct page *referer = c_initialReferer();
+    session = c_newSession();
+    if (logpath != NULL) session = c_enableLogging(session);
+    referer = c_initialReferer();
 
     if (use_espeak) speak_err = speak_initialize();
-    char *ssml, **links, *uri;
     if (optind >= argc) {
         // No URLs specified, restore previous session or goto about:welcome
-        uri = c_lastVisited("about:welcome");
-        goto read_uri;
-    }
-    for (int i = optind; i < argc; i++) {
-        uri = argv[i];
-
-read_uri:
-        if (use_espeak && speak_err == 0) speak_text(uri, espeakRATE, 10);
-        #ifdef WITH_SPEECHD
-        else if (spd_conn != NULL) spd_say(spd_conn, SPD_MESSAGE, uri);
-        #endif
-        else printf("%s\n", argv[i]);
-
-        if (logpath != NULL) session = c_enableLogging(session);
+        read_page(c_lastVisited("about:welcome"), 1);
+    } else for (int i = optind; i < argc; i++) read_page(argv[i], i+1 == argc);
 
-        struct page *page = c_fetchURL(session, mimes, referer, uri);
-        ssml = c_renderDoc(session, page, use_espeak);
-        links = c_extractLinks(page);
-
-        if (logpath != NULL) c_writeLog(logpath, session);
-
-        if (fd_ssml != NULL) fprintf(fd_ssml, "%s\n", ssml);
-        if (read_keyboard && strcmp(uri, "about:welcome")) select_link(links, "");
-        if (fd_links != NULL) write_links(fd_links, links);
-        if (use_espeak & speak_err == 0) speak(ssml, "main", NULL);
-        #ifdef WITH_SPEECHD
-        if (spd_conn != NULL) spd_say(spd_conn, SPD_MESSAGE, ssml);
-        #endif
-
-        c_freePage(page);
-    }
-
-    uri = NULL;
-    if (use_espeak & speak_err == 0) speak_err = speak_finalize(ssml, links, &uri);
-    if (uri != NULL) goto read_uri;
+    g_main_loop_run(loop);
 
     #ifdef WITH_SPEECHD
     if (spd_conn != NULL) spd_close(spd_conn);
     #endif
 
+    espeak_ng_STATUS result = espeak_ng_Synchronize();
+    if (result != ENS_OK) {
+        espeak_ng_PrintStatusCodeMessage(result, stderr, context);
+        return 4;
+    }
+    if (path_wav != NULL) sf_close(fd_wav);
+    espeak_ng_Terminate();
+
     c_freePage(referer);
     c_freeSession(session);
     hs_exit();