]> git.ipfire.org Git - thirdparty/plymouth.git/commitdiff
[libplybootsplash] Add keyboard class
authorRay Strode <rstrode@redhat.com>
Fri, 21 Aug 2009 23:21:53 +0000 (19:21 -0400)
committerRay Strode <rstrode@redhat.com>
Mon, 28 Sep 2009 15:23:36 +0000 (11:23 -0400)
This is the input portion of the window class.  With this commit
and subsequent commits to split out the output portions, we should
be able to drop the window class.

This will give us the flexibility we need for multi-head rendering.

src/libplybootsplash/Makefile.am
src/libplybootsplash/ply-keyboard.c [new file with mode: 0644]
src/libplybootsplash/ply-keyboard.h [new file with mode: 0644]

index 7b8c5c1663a8ba668b28b83f3e7beb476cdff2b8..51b9b842d7cca8971c72da77d028ebe46a27a70e 100644 (file)
@@ -12,6 +12,7 @@ libplybootsplash_HEADERS = \
                    ply-boot-splash-plugin.h                                  \
                    ply-entry.h                                               \
                    ply-image.h                                               \
+                   ply-keyboard.h                                            \
                    ply-label.h                                               \
                    ply-label-plugin.h                                        \
                    ply-pixel-buffer.h                                        \
@@ -35,6 +36,7 @@ libplybootsplash_la_SOURCES = \
                    $(libplybootsplash_HEADERS)                              \
                    ply-entry.c                                              \
                    ply-image.c                                              \
+                   ply-keyboard.c                                           \
                    ply-label.c                                              \
                    ply-progress-bar.c                                       \
                    ply-throbber.c                                           \
diff --git a/src/libplybootsplash/ply-keyboard.c b/src/libplybootsplash/ply-keyboard.c
new file mode 100644 (file)
index 0000000..375ddd5
--- /dev/null
@@ -0,0 +1,583 @@
+/* ply-keyboard.h - APIs for putting up a keyboard screen
+ *
+ * Copyright (C) 2009 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ *
+ * Written by: Ray Strode <rstrode@redhat.com>
+ */
+#include "config.h"
+#include "ply-keyboard.h"
+
+#include <assert.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <wchar.h>
+
+#include "ply-buffer.h"
+#include "ply-event-loop.h"
+#include "ply-list.h"
+#include "ply-logger.h"
+#include "ply-renderer.h"
+#include "ply-terminal.h"
+#include "ply-utils.h"
+
+#define KEY_CTRL_U ('\100' ^'U')
+#define KEY_CTRL_W ('\100' ^'W')
+#define KEY_CTRL_V ('\100' ^'V')
+#define KEY_ESCAPE ('\100' ^'[')
+#define KEY_RETURN '\r'
+#define KEY_BACKSPACE '\177'
+
+typedef void (* ply_keyboard_handler_t) (void *);
+
+typedef struct
+{
+  ply_keyboard_handler_t function;
+  void *user_data;
+} ply_keyboard_closure_t;
+
+typedef enum
+{
+  PLY_KEYBOARD_PROVIDER_TYPE_TERMINAL,
+  PLY_KEYBOARD_PROVIDER_TYPE_RENDERER
+} ply_keyboard_provider_type_t;
+
+typedef struct
+{
+  ply_terminal_t *terminal;
+  ply_fd_watch_t *input_watch;
+  ply_buffer_t   *key_buffer;
+} ply_keyboard_terminal_provider_t;
+
+typedef struct
+{
+  ply_renderer_t              *renderer;
+  ply_renderer_input_source_t *input_source;
+} ply_keyboard_renderer_provider_t;
+
+typedef  union {
+  ply_keyboard_renderer_provider_t *if_renderer;
+  ply_keyboard_terminal_provider_t *if_terminal;
+} ply_keyboard_provider_t;
+
+struct _ply_keyboard
+{
+  ply_event_loop_t *loop;
+
+  ply_keyboard_provider_type_t provider_type;
+  ply_keyboard_provider_t provider;
+
+  ply_buffer_t     *line_buffer;
+
+  ply_list_t *keyboard_input_handler_list;
+  ply_list_t *backspace_handler_list;
+  ply_list_t *escape_handler_list;
+  ply_list_t *enter_handler_list;
+};
+
+ply_keyboard_t *
+ply_keyboard_new_for_terminal (ply_terminal_t *terminal)
+{
+  ply_keyboard_t *keyboard;
+
+  keyboard = calloc (1, sizeof (ply_keyboard_t));
+  keyboard->line_buffer = ply_buffer_new ();
+  keyboard->keyboard_input_handler_list = ply_list_new ();
+  keyboard->backspace_handler_list = ply_list_new ();
+  keyboard->escape_handler_list = ply_list_new ();
+  keyboard->enter_handler_list = ply_list_new ();
+  keyboard->provider_type = PLY_KEYBOARD_PROVIDER_TYPE_TERMINAL;
+  keyboard->provider.if_terminal = calloc (1, sizeof (ply_keyboard_terminal_provider_t));
+  keyboard->provider.if_terminal->terminal = terminal;
+  keyboard->provider.if_terminal->key_buffer = ply_buffer_new ();
+
+  keyboard->loop = ply_event_loop_get_default ();
+
+  return keyboard;
+}
+
+ply_keyboard_t *
+ply_keyboard_new_for_renderer (ply_renderer_t *renderer)
+{
+  ply_keyboard_t *keyboard;
+  ply_renderer_input_source_t *input_source;
+
+  keyboard = calloc (1, sizeof (ply_keyboard_t));
+  keyboard->line_buffer = ply_buffer_new ();
+  keyboard->keyboard_input_handler_list = ply_list_new ();
+  keyboard->backspace_handler_list = ply_list_new ();
+  keyboard->escape_handler_list = ply_list_new ();
+  keyboard->enter_handler_list = ply_list_new ();
+  keyboard->provider_type = PLY_KEYBOARD_PROVIDER_TYPE_RENDERER;
+  keyboard->provider.if_renderer = calloc (1, sizeof (ply_keyboard_renderer_provider_t));
+  keyboard->provider.if_renderer->renderer = renderer;
+
+  input_source = ply_renderer_get_input_source (renderer);
+
+  keyboard->provider.if_renderer->input_source = input_source;
+
+  keyboard->loop = ply_event_loop_get_default ();
+
+  return keyboard;
+}
+
+static void
+process_backspace (ply_keyboard_t *keyboard)
+{
+  size_t bytes_to_remove;
+  ssize_t previous_character_size;
+  const char *bytes;
+  size_t size;
+  ply_list_node_t *node;
+
+  bytes = ply_buffer_get_bytes (keyboard->line_buffer);
+  size = ply_buffer_get_size (keyboard->line_buffer);
+
+  bytes_to_remove = MIN (size, PLY_UTF8_CHARACTER_SIZE_MAX);
+  while ((previous_character_size = ply_utf8_character_get_size (bytes + size - bytes_to_remove, bytes_to_remove)) < (ssize_t) bytes_to_remove)
+    {
+      if (previous_character_size > 0)
+        bytes_to_remove -= previous_character_size;
+      else
+        bytes_to_remove--;
+    }
+
+  if (bytes_to_remove <= size)
+    ply_buffer_remove_bytes_at_end (keyboard->line_buffer, bytes_to_remove);
+
+  for (node = ply_list_get_first_node(keyboard->backspace_handler_list);
+       node; node = ply_list_get_next_node(keyboard->backspace_handler_list, node))
+    {
+      ply_keyboard_closure_t *closure = ply_list_node_get_data (node);
+      ply_keyboard_backspace_handler_t backspace_handler =
+        (ply_keyboard_backspace_handler_t) closure->function;
+      backspace_handler (closure->user_data);
+    }
+}
+
+static void
+process_line_erase (ply_keyboard_t *keyboard)
+{
+  size_t size;
+
+  while ((size = ply_buffer_get_size (keyboard->line_buffer)) > 0)
+    process_backspace (keyboard);
+}
+
+static void
+process_keyboard_input (ply_keyboard_t *keyboard,
+                        const char   *keyboard_input,
+                        size_t        character_size)
+{
+  wchar_t key;
+  ply_list_node_t *node;
+
+  if ((ssize_t) mbrtowc (&key, keyboard_input, character_size, NULL) > 0)
+    {
+      switch (key)
+        {
+          case KEY_CTRL_U:
+          case KEY_CTRL_W:
+            ply_trace ("erase line!");
+            process_line_erase (keyboard);
+            return;
+
+          case KEY_CTRL_V:
+            ply_trace ("toggle verbose mode!");
+            ply_toggle_tracing ();
+            ply_trace ("verbose mode toggled!");
+            return;
+
+          case KEY_ESCAPE:
+            ply_trace ("escape key!");
+            for (node = ply_list_get_first_node(keyboard->escape_handler_list);
+                 node; node = ply_list_get_next_node(keyboard->escape_handler_list, node))
+              {
+                ply_keyboard_closure_t *closure = ply_list_node_get_data (node);
+                ply_keyboard_escape_handler_t escape_handler = (ply_keyboard_escape_handler_t) closure->function;
+                escape_handler (closure->user_data);
+              }
+
+            ply_trace ("end escape key handler");
+            return;
+
+          case KEY_BACKSPACE:
+            ply_trace ("backspace key!");
+            process_backspace (keyboard);
+            return;
+
+          case KEY_RETURN:
+            ply_trace ("return key!");
+
+            for (node = ply_list_get_first_node(keyboard->enter_handler_list);
+                 node; node = ply_list_get_next_node(keyboard->enter_handler_list, node))
+              {
+                ply_keyboard_closure_t *closure = ply_list_node_get_data (node);
+                ply_keyboard_enter_handler_t enter_handler = (ply_keyboard_enter_handler_t)  closure->function;
+                enter_handler (closure->user_data, ply_buffer_get_bytes (keyboard->line_buffer));
+              }
+            ply_buffer_clear (keyboard->line_buffer);
+            return;
+
+          default:
+            ply_buffer_append_bytes (keyboard->line_buffer,
+                                     keyboard_input, character_size);
+            break;
+        }
+    }
+
+  for (node = ply_list_get_first_node(keyboard->keyboard_input_handler_list);
+       node; node = ply_list_get_next_node(keyboard->keyboard_input_handler_list, node))
+    {
+      ply_keyboard_closure_t *closure = ply_list_node_get_data (node);
+      ply_keyboard_input_handler_t keyboard_input_handler =
+        (ply_keyboard_input_handler_t) closure->function;
+
+      keyboard_input_handler (closure->user_data,
+                              keyboard_input, character_size);
+    }
+}
+
+static void
+on_key_event (ply_keyboard_t   *keyboard,
+              ply_buffer_t     *buffer)
+{
+  const char *bytes;
+  size_t size, i;
+
+  bytes = ply_buffer_get_bytes (buffer);
+  size = ply_buffer_get_size (buffer);
+
+  i = 0;
+  while (i < size)
+    {
+      ssize_t character_size;
+      char *keyboard_input;
+
+      character_size = (ssize_t) ply_utf8_character_get_size (bytes + i, size - i);
+
+      if (character_size < 0)
+        break;
+
+      /* If we're at a NUL character walk through it
+      */
+      if (character_size == 0)
+        {
+          i++;
+          continue;
+        }
+
+      keyboard_input = strndup (bytes + i, character_size);
+
+      process_keyboard_input (keyboard, keyboard_input, character_size);
+
+      i += character_size;
+
+      free (keyboard_input);
+    }
+
+  if (i > 0)
+    ply_buffer_remove_bytes (buffer, i);
+}
+
+static bool
+ply_keyboard_watch_for_renderer_input (ply_keyboard_t *keyboard)
+{
+  assert (keyboard != NULL);
+
+  if (!ply_renderer_open_input_source (keyboard->provider.if_renderer->renderer,
+                                       keyboard->provider.if_renderer->input_source))
+    return false;
+
+  ply_renderer_set_handler_for_input_source (keyboard->provider.if_renderer->renderer,
+                                             keyboard->provider.if_renderer->input_source,
+                                             (ply_renderer_input_source_handler_t)
+                                             on_key_event,
+                                             keyboard);
+  return true;
+}
+
+static void
+ply_keyboard_stop_watching_for_renderer_input (ply_keyboard_t *keyboard)
+{
+  ply_renderer_set_handler_for_input_source (keyboard->provider.if_renderer->renderer,
+                                             keyboard->provider.if_renderer->input_source,
+                                             (ply_renderer_input_source_handler_t)
+                                             NULL, NULL);
+
+  ply_renderer_close_input_source (keyboard->provider.if_renderer->renderer,
+                                   keyboard->provider.if_renderer->input_source);
+}
+
+static void
+on_terminal_data (ply_keyboard_t *keyboard)
+{
+  int terminal_fd;
+
+  terminal_fd = ply_terminal_get_fd (keyboard->provider.if_terminal->terminal);
+  ply_buffer_append_from_fd (keyboard->provider.if_terminal->key_buffer,
+                             terminal_fd);
+  on_key_event (keyboard, keyboard->provider.if_terminal->key_buffer);
+}
+
+static bool
+ply_keyboard_watch_for_terminal_input (ply_keyboard_t *keyboard)
+{
+  int terminal_fd;
+
+  assert (keyboard != NULL);
+
+  terminal_fd = ply_terminal_get_fd (keyboard->provider.if_terminal->terminal);
+  keyboard->provider.if_terminal->input_watch = ply_event_loop_watch_fd (keyboard->loop, terminal_fd, PLY_EVENT_LOOP_FD_STATUS_HAS_DATA,
+                                                                          (ply_event_handler_t) on_terminal_data, NULL, keyboard);
+
+  return true;
+}
+
+static void
+ply_keyboard_stop_watching_for_terminal_input (ply_keyboard_t *keyboard)
+{
+  ply_event_loop_stop_watching_fd (keyboard->loop,
+                                   keyboard->provider.if_terminal->input_watch);
+  keyboard->provider.if_terminal->input_watch = NULL;
+}
+
+bool
+ply_keyboard_watch_for_input (ply_keyboard_t *keyboard)
+{
+  assert (keyboard != NULL);
+
+  switch (keyboard->provider_type)
+    {
+      case PLY_KEYBOARD_PROVIDER_TYPE_RENDERER:
+        return ply_keyboard_watch_for_renderer_input (keyboard);
+
+      case PLY_KEYBOARD_PROVIDER_TYPE_TERMINAL:
+        return ply_keyboard_watch_for_terminal_input (keyboard);
+    }
+
+  return false;
+}
+
+void
+ply_keyboard_stop_watching_for_input (ply_keyboard_t *keyboard)
+{
+  assert (keyboard != NULL);
+
+  switch (keyboard->provider_type)
+    {
+      case PLY_KEYBOARD_PROVIDER_TYPE_RENDERER:
+        ply_keyboard_stop_watching_for_renderer_input (keyboard);
+        break;
+
+      case PLY_KEYBOARD_PROVIDER_TYPE_TERMINAL:
+        ply_keyboard_stop_watching_for_terminal_input (keyboard);
+        break;
+    }
+
+}
+
+void
+ply_keyboard_free (ply_keyboard_t *keyboard)
+{
+  if (keyboard == NULL)
+    return;
+
+  ply_keyboard_stop_watching_for_input (keyboard);
+
+  ply_buffer_free (keyboard->line_buffer);
+
+  if (keyboard->provider_type == PLY_KEYBOARD_PROVIDER_TYPE_RENDERER)
+    {
+      free (keyboard->provider.if_renderer);
+    }
+  else
+    {
+      ply_buffer_free (keyboard->provider.if_terminal->key_buffer);
+      free (keyboard->provider.if_terminal);
+    }
+
+  free (keyboard);
+}
+
+static ply_keyboard_closure_t *
+ply_keyboard_closure_new (ply_keyboard_handler_t  function,
+                          void                   *user_data)
+{
+  ply_keyboard_closure_t *closure = calloc (1, sizeof (ply_keyboard_closure_t));
+  closure->function = function;
+  closure->user_data = user_data;
+  return closure;
+}
+
+
+static void
+ply_keyboard_closure_free (ply_keyboard_closure_t *closure)
+{
+  free (closure);
+}
+
+void
+ply_keyboard_add_input_handler (ply_keyboard_t               *keyboard,
+                                ply_keyboard_input_handler_t  input_handler,
+                                void                         *user_data)
+{
+  ply_keyboard_closure_t *closure;
+
+  assert (keyboard != NULL);
+
+  closure = ply_keyboard_closure_new ((ply_keyboard_handler_t) input_handler,
+                                      user_data);
+  ply_list_append_data (keyboard->keyboard_input_handler_list, closure);
+}
+
+void
+ply_keyboard_remove_input_handler (ply_keyboard_t               *keyboard,
+                                   ply_keyboard_input_handler_t  input_handler)
+{
+  ply_list_node_t *node;
+
+  assert (keyboard != NULL);
+
+  for (node = ply_list_get_first_node(keyboard->keyboard_input_handler_list);
+       node; node = ply_list_get_next_node(keyboard->keyboard_input_handler_list, node))
+    {
+      ply_keyboard_closure_t *closure = ply_list_node_get_data (node);
+      if ((ply_keyboard_input_handler_t) closure->function == input_handler)
+        {
+          ply_keyboard_closure_free (closure);
+          ply_list_remove_node (keyboard->keyboard_input_handler_list, node);
+          return;
+        }
+    }
+}
+
+void
+ply_keyboard_add_backspace_handler (ply_keyboard_t                   *keyboard,
+                                    ply_keyboard_backspace_handler_t  backspace_handler,
+                                    void                             *user_data)
+{
+  ply_keyboard_closure_t *closure;
+
+  assert (keyboard != NULL);
+
+  closure = ply_keyboard_closure_new ((ply_keyboard_handler_t) backspace_handler,
+                                      user_data);
+  ply_list_append_data (keyboard->backspace_handler_list, closure);
+}
+
+
+void
+ply_keyboard_remove_backspace_handler (ply_keyboard_t                   *keyboard,
+                                       ply_keyboard_backspace_handler_t  backspace_handler)
+{
+  ply_list_node_t *node;
+
+  assert (keyboard != NULL);
+
+  for (node = ply_list_get_first_node(keyboard->backspace_handler_list);
+       node; node = ply_list_get_next_node(keyboard->backspace_handler_list, node))
+    {
+      ply_keyboard_closure_t *closure = ply_list_node_get_data (node);
+      if ((ply_keyboard_backspace_handler_t) closure->function == backspace_handler)
+        {
+          ply_keyboard_closure_free (closure);
+          ply_list_remove_node (keyboard->backspace_handler_list, node);
+          return;
+        }
+    }
+}
+
+void
+ply_keyboard_add_escape_handler (ply_keyboard_t                *keyboard,
+                                 ply_keyboard_escape_handler_t  escape_handler,
+                                 void                          *user_data)
+{
+  ply_keyboard_closure_t *closure;
+
+  assert (keyboard != NULL);
+
+  closure = ply_keyboard_closure_new ((ply_keyboard_handler_t)  escape_handler,
+                                      user_data);
+  ply_list_append_data (keyboard->escape_handler_list, closure);
+}
+
+
+void
+ply_keyboard_remove_escape_handler (ply_keyboard_t                *keyboard,
+                                    ply_keyboard_escape_handler_t  escape_handler)
+{
+  ply_list_node_t *node;
+
+  assert (keyboard != NULL);
+
+  for (node = ply_list_get_first_node(keyboard->escape_handler_list);
+       node; node = ply_list_get_next_node(keyboard->escape_handler_list, node))
+    {
+      ply_keyboard_closure_t *closure = ply_list_node_get_data (node);
+      if ((ply_keyboard_escape_handler_t) closure->function == escape_handler)
+        {
+          ply_keyboard_closure_free (closure);
+          ply_list_remove_node (keyboard->escape_handler_list, node);
+          return;
+        }
+    }
+}
+
+void
+ply_keyboard_add_enter_handler (ply_keyboard_t               *keyboard,
+                                ply_keyboard_enter_handler_t  enter_handler,
+                                void                         *user_data)
+{
+  ply_keyboard_closure_t *closure;
+
+  assert (keyboard != NULL);
+
+  closure = ply_keyboard_closure_new ((ply_keyboard_handler_t) enter_handler,
+                                      user_data);
+
+  ply_list_append_data (keyboard->enter_handler_list, closure);
+}
+
+void
+ply_keyboard_remove_enter_handler (ply_keyboard_t               *keyboard,
+                                   ply_keyboard_enter_handler_t  enter_handler)
+{
+  ply_list_node_t *node;
+
+  assert (keyboard != NULL);
+
+  for (node = ply_list_get_first_node(keyboard->enter_handler_list);
+       node; node = ply_list_get_next_node(keyboard->enter_handler_list, node))
+    {
+      ply_keyboard_closure_t *closure = ply_list_node_get_data (node);
+      if ((ply_keyboard_enter_handler_t) closure->function == enter_handler)
+        {
+          ply_keyboard_closure_free (closure);
+          ply_list_remove_node (keyboard->enter_handler_list, node);
+          return;
+        }
+    }
+}
+
+/* vim: set ts=4 sw=4 et ai ci cino={.5s,^-2,+.5s,t0,g0,e-2,n-2,p2s,(0,=.5s,:.5s */
diff --git a/src/libplybootsplash/ply-keyboard.h b/src/libplybootsplash/ply-keyboard.h
new file mode 100644 (file)
index 0000000..74683cf
--- /dev/null
@@ -0,0 +1,78 @@
+/* ply-keyboard.h - APIs for putting up a splash screen
+ *
+ * Copyright (C) 2009 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ *
+ * Written By: Ray Strode <rstrode@redhat.com>
+ */
+#ifndef PLY_KEYBOARD_H
+#define PLY_KEYBOARD_H
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <unistd.h>
+
+#include "ply-buffer.h"
+#include "ply-event-loop.h"
+#include "ply-renderer.h"
+
+typedef struct _ply_keyboard ply_keyboard_t;
+
+typedef void (* ply_keyboard_input_handler_t) (void       *user_data,
+                                               const char *keyboard_input,
+                                               size_t      character_size);
+
+typedef void (* ply_keyboard_backspace_handler_t) (void *user_data);
+
+typedef void (* ply_keyboard_escape_handler_t) (void *user_data);
+
+typedef void (* ply_keyboard_enter_handler_t) (void       *user_data,
+                                               const char *line);
+
+#ifndef PLY_HIDE_FUNCTION_DECLARATIONS
+ply_keyboard_t *ply_keyboard_new_for_terminal (ply_terminal_t *terminal);
+ply_keyboard_t *ply_keyboard_new_for_renderer (ply_renderer_t *renderer);
+void ply_keyboard_free (ply_keyboard_t *keyboard);
+
+void ply_keyboard_add_input_handler (ply_keyboard_t               *keyboard,
+                                     ply_keyboard_input_handler_t  input_handler,
+                                     void                         *user_data);
+void ply_keyboard_remove_input_handler (ply_keyboard_t               *keyboard,
+                                        ply_keyboard_input_handler_t  input_handler);
+void ply_keyboard_add_backspace_handler (ply_keyboard_t                   *keyboard,
+                                         ply_keyboard_backspace_handler_t  backspace_handler,
+                                         void                             *user_data);
+void ply_keyboard_remove_backspace_handler (ply_keyboard_t                   *keyboard,
+                                            ply_keyboard_backspace_handler_t  backspace_handler);
+void ply_keyboard_add_escape_handler (ply_keyboard_t                *keyboard,
+                                      ply_keyboard_escape_handler_t  escape_handler,
+                                      void                          *user_data);
+void ply_keyboard_remove_escape_handler (ply_keyboard_t                *keyboard,
+                                         ply_keyboard_escape_handler_t  escape_handler);
+void ply_keyboard_add_enter_handler (ply_keyboard_t               *keyboard,
+                                     ply_keyboard_enter_handler_t  enter_handler,
+                                     void                         *user_data);
+void ply_keyboard_remove_enter_handler (ply_keyboard_t               *keyboard,
+                                        ply_keyboard_enter_handler_t  enter_handler);
+
+bool ply_keyboard_watch_for_input (ply_keyboard_t *keyboard);
+void ply_keyboard_stop_watching_for_input (ply_keyboard_t *keyboard);
+
+#endif
+
+#endif /* PLY_KEYBOARD_H */
+/* vim: set ts=4 sw=4 et ai ci cino={.5s,^-2,+.5s,t0,g0,e-2,n-2,p2s,(0,=.5s,:.5s */