diff --git a/data/gtk/help-overlay.blp b/data/gtk/help-overlay.blp
new file mode 100644
index 0000000000000000000000000000000000000000..633ef9ac6e937bd5db92bcb968238ad53740d3a1
--- /dev/null
+++ b/data/gtk/help-overlay.blp
@@ -0,0 +1,32 @@
+// SPDX-FileCopyrightText: 2022 Bruce Cowan <bruce@bcowan.me.uk>
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+using Gtk 4.0;
+
+ShortcutsWindow help_overlay {
+  ShortcutsSection {
+    ShortcutsGroup {
+      title: "Application";
+
+      ShortcutsShortcut {
+        title: "Preferences";
+        action-name: "app.prefs";
+      }
+    }
+
+    ShortcutsGroup {
+      title: "Score";
+
+      ShortcutsShortcut {
+        title: "Increment score";
+        action-name: "win.score-changed::up";
+      }
+
+      ShortcutsShortcut {
+        title: "Decrement score";
+        action-name: "win.score-changed::down";
+      }
+    }
+  }
+}
diff --git a/data/meson.build b/data/meson.build
index 2632f1110b0c369fef9b9b7dbfcbf4d3c70fa5ec..fd78f0c6b53c71cc0bb8f1fefeba4a213c1b8497 100644
--- a/data/meson.build
+++ b/data/meson.build
@@ -4,6 +4,7 @@
 
 blueprints = custom_target('blueprints',
   input: files(
+    'gtk/help-overlay.blp',
     'prefs.blp',
     'window.blp'
   ),
diff --git a/data/rugby.gresource.xml b/data/rugby.gresource.xml
index 1c63d2e60db4711fc04b175691fd79aba748e10a..eb97f5fd18ae0670f2408d6238e0cfd827aa25f0 100644
--- a/data/rugby.gresource.xml
+++ b/data/rugby.gresource.xml
@@ -5,7 +5,8 @@
   SPDX-License-Identifier: GPL-3.0-or-later
 -->
 <gresources>
-  <gresource prefix="/uk/me/bcowan/rugby">
+  <gresource prefix="/uk/me/bcowan/Rugby">
+    <file preprocess="xml-stripblanks" compressed="true">gtk/help-overlay.ui</file>
     <file preprocess="xml-stripblanks" compressed="true">prefs.ui</file>
     <file preprocess="xml-stripblanks" compressed="true">score-item.ui</file>
     <file preprocess="xml-stripblanks" compressed="true">window.ui</file>
diff --git a/data/window.blp b/data/window.blp
index bba80b1b0d4db8cb3ee0961994fc76628678bd52..6c680519943ca5f646629fa914cdd90a19de8667 100644
--- a/data/window.blp
+++ b/data/window.blp
@@ -27,6 +27,7 @@ template RugbyAppWindow : Adw.ApplicationWindow {
       MenuButton menu_button {
         direction: none;
         menu-model: app_menu;
+        tooltip-text: "Main Menu";
       }
     }
 
@@ -45,7 +46,7 @@ template RugbyAppWindow : Adw.ApplicationWindow {
             };
           };
           factory: BuilderListItemFactory {
-            resource: "/uk/me/bcowan/rugby/score-item.ui";
+            resource: "/uk/me/bcowan/Rugby/score-item.ui";
           };
         }
       }
@@ -56,8 +57,7 @@ template RugbyAppWindow : Adw.ApplicationWindow {
 menu app_menu {
   section {
     item ("_Preferences", "app.prefs")
-  }
-  section {
+    item ("_Keyboard Shortcuts", "win.show-help-overlay")
     item ("_About Rugby", "app.about")
   }
 }
diff --git a/src/main.c b/src/main.c
index 5b992ab1fe8a7c9b4753106b2685f281f2f297a0..081eb62890cbd288b57f3c708e486ddf11a1924d 100644
--- a/src/main.c
+++ b/src/main.c
@@ -68,6 +68,18 @@ on_startup (GApplication          *app,
                                      app_entries,
                                      G_N_ELEMENTS (app_entries),
                                      app);
+    gtk_application_set_accels_for_action (GTK_APPLICATION (app),
+                                           "win.show-primary-menu",
+                                           (const char*[]) { "F10", NULL });
+    gtk_application_set_accels_for_action (GTK_APPLICATION (app),
+                                           "app.prefs",
+                                           (const char*[]) { "<Ctrl>comma", NULL });
+    gtk_application_set_accels_for_action (GTK_APPLICATION (app),
+                                           "win.score-changed::up",
+                                           (const char*[]) { "<Ctrl>Up", "<Ctrl>Right", NULL });
+    gtk_application_set_accels_for_action (GTK_APPLICATION (app),
+                                           "win.score-changed::down",
+                                           (const char*[]) { "<Ctrl>Down", "<Ctrl>Left", NULL });
 }
 
 int
diff --git a/src/rugby-app-window.c b/src/rugby-app-window.c
index 1db52209e716863f9d822c36a35fac0a72cb866a..d9ec1f2b3c42f02efbe5939c706d14967a2deabb 100644
--- a/src/rugby-app-window.c
+++ b/src/rugby-app-window.c
@@ -15,6 +15,9 @@
 struct _RugbyAppWindow
 {
     AdwApplicationWindow parent;
+
+    GtkWidget *scorespin;
+    GtkWidget *menu_button;
 };
 
 G_DEFINE_TYPE (RugbyAppWindow, rugby_app_window, ADW_TYPE_APPLICATION_WINDOW)
@@ -70,10 +73,47 @@ item_tooltip_cb (GtkListItem *item)
     return g_string_free (tooltip, FALSE);
 }
 
+static void
+activate_score_changed (G_GNUC_UNUSED GSimpleAction *action,
+                                      GVariant      *parameter,
+                                      gpointer       user_data)
+{
+    RugbyAppWindow *self = RUGBY_APP_WINDOW (user_data);
+
+    double current_value = gtk_spin_button_get_value (GTK_SPIN_BUTTON (self->scorespin));
+    const char *direction = g_variant_get_string (parameter, NULL);
+
+    if (g_strcmp0 (direction, "up") == 0)
+        gtk_spin_button_set_value (GTK_SPIN_BUTTON (self->scorespin), current_value + 1.0);
+    else if (g_strcmp0 (direction, "down") == 0)
+        gtk_spin_button_set_value (GTK_SPIN_BUTTON (self->scorespin), current_value - 1.0);
+    else
+        g_assert_not_reached ();
+}
+
+static void
+activate_show_primary_menu (G_GNUC_UNUSED GSimpleAction *action,
+                            G_GNUC_UNUSED GVariant      *parameter,
+                                          gpointer       user_data)
+{
+    RugbyAppWindow *self = RUGBY_APP_WINDOW (user_data);
+    gtk_menu_button_popup (GTK_MENU_BUTTON (self->menu_button));
+}
+
+const GActionEntry win_entries[] = {
+    { .name = "score-changed", .activate = activate_score_changed, .parameter_type = "s" },
+    { .name = "show-primary-menu", .activate = activate_show_primary_menu },
+};
+
 static void
 rugby_app_window_init (RugbyAppWindow *self)
 {
     gtk_widget_init_template (GTK_WIDGET (self));
+
+    g_action_map_add_action_entries (G_ACTION_MAP (self),
+                                     win_entries,
+                                     G_N_ELEMENTS (win_entries),
+                                     self);
 }
 
 static void
@@ -85,7 +125,10 @@ rugby_app_window_class_init (RugbyAppWindowClass *klass)
     g_type_ensure (RUGBY_TYPE_LIST_STORE);
 
     gtk_widget_class_set_template_from_resource (widget_class,
-                                                 "/uk/me/bcowan/rugby/window.ui");
+                                                 "/uk/me/bcowan/Rugby/window.ui");
+
+    gtk_widget_class_bind_template_child (widget_class, RugbyAppWindow, scorespin);
+    gtk_widget_class_bind_template_child (widget_class, RugbyAppWindow, menu_button);
 
     gtk_widget_class_bind_template_callback (widget_class, item_tooltip_cb);
 }
diff --git a/src/rugby-pref-window.c b/src/rugby-pref-window.c
index 423471074634eaffb4fde57119d8606059f09c03..79b0b08b87e9df7adc957245aecff1665bea35de 100644
--- a/src/rugby-pref-window.c
+++ b/src/rugby-pref-window.c
@@ -38,7 +38,7 @@ rugby_pref_window_class_init (RugbyPrefWindowClass *klass)
   object_class->dispose = rugby_pref_window_dispose;
 
   gtk_widget_class_set_template_from_resource (widget_class,
-                                               "/uk/me/bcowan/rugby/prefs.ui");
+                                               "/uk/me/bcowan/Rugby/prefs.ui");
 
   gtk_widget_class_bind_template_child (widget_class, RugbyPrefWindow, try_spin);
   gtk_widget_class_bind_template_child (widget_class, RugbyPrefWindow, utry_spin);