diff --git a/data/cintiq-pro-13.tablet b/data/cintiq-pro-13.tablet
index 4b0b773ea..a98180718 100644
--- a/data/cintiq-pro-13.tablet
+++ b/data/cintiq-pro-13.tablet
@@ -43,3 +43,7 @@ Stylus=true
 Reversible=false
 Touch=true
 Ring=false
+
+[Keys]
+# first key is in-kernel display toggle
+KeyCodes=0;KEY_CONTROLPANEL;KEY_ONSCREEN_KEYBOARD;KEY_BUTTONCONFIG;SW_MUTE_DEVICE
diff --git a/data/wacom.example b/data/wacom.example
index d4366c3c1..7c16f01f4 100644
--- a/data/wacom.example
+++ b/data/wacom.example
@@ -210,3 +210,10 @@ Touchstrip2=J
 # We assume the same number of modes for each of the touchstrips
 # if there is more than one
 StripsNumModes=4
+
+
+# Metadata about the keys on the tablet
+[Keys]
+# The evdev codes for the keys (if any) in order from left to right.
+# Keys that have a code of zero do not produce any events.
+KeyCodes=0;KEY_CONTROLPANEL;KEY_ONSCREEN_KEYBOARD;KEY_BUTTONCONFIG;SW_MUTE_DEVICE
diff --git a/libwacom/libwacom-database.c b/libwacom/libwacom-database.c
index eec096353..2c17e0d71 100644
--- a/libwacom/libwacom-database.c
+++ b/libwacom/libwacom-database.c
@@ -45,6 +45,7 @@
 #define FEATURES_GROUP "Features"
 #define DEVICE_GROUP "Device"
 #define BUTTONS_GROUP "Buttons"
+#define KEYS_GROUP "Keys"
 
 static WacomClass
 libwacom_class_string_to_enum(const char *class)
@@ -493,6 +494,50 @@ set_button_codes_from_string(WacomDevice *device, char **strvals)
 	return success;
 }
 
+static inline bool
+set_key_codes_from_string(WacomDevice *device, char **strvals)
+{
+	bool success = false;
+	assert(strvals);
+
+	for (unsigned int idx = 0; strvals[idx]; idx++) {
+		const char *str = strvals[idx];
+		int code = -1;
+		int type = -1;
+
+		if (!str) {
+			g_error("%s: Missing KeyCode for key %d, ignoring all codes\n",
+				device->name, idx);
+			goto out;
+		} else if (g_str_has_prefix(str, "KEY")) {
+			type = EV_KEY;
+			code = libevdev_event_code_from_code_name(str);
+		} else if (g_str_has_prefix(str, "SW")) {
+			type = EV_SW;
+			code = libevdev_event_code_from_code_name(str);
+		} else {
+			if (safe_atoi_base (strvals[idx], &code, 16))
+				type = EV_KEY;
+		}
+
+		if (code == -1 || type == -1) {
+			g_warning ("%s: Invalid KeyCode %s, ignoring all codes\n", device->name, str);
+			goto out;
+		}
+
+		device->keycodes[idx].type = type;
+		device->keycodes[idx].code = code;
+		device->num_keycodes = idx + 1;
+	}
+
+	success = true;
+out:
+	if (!success) {
+		memset(device->keycodes, 0, sizeof(device->keycodes));
+	}
+	return success;
+}
+
 static inline void
 set_button_codes_from_heuristics(WacomDevice *device)
 {
@@ -604,6 +649,30 @@ libwacom_parse_buttons(WacomDevice *device,
 	device->strips_num_modes = libwacom_parse_num_modes(device, keyfile, "StripsNumModes", WACOM_BUTTON_TOUCHSTRIP_MODESWITCH);
 }
 
+static void
+libwacom_parse_key_codes(WacomDevice *device,
+			 GKeyFile    *keyfile)
+{
+	char **vals;
+
+	vals = g_key_file_get_string_list(keyfile, KEYS_GROUP, "KeyCodes", NULL, NULL);
+	if (vals)
+		set_key_codes_from_string(device, vals);
+
+	g_strfreev (vals);
+}
+
+static void
+libwacom_parse_keys(WacomDevice *device,
+		    GKeyFile    *keyfile)
+{
+	if (!g_key_file_has_group(keyfile, KEYS_GROUP))
+		return;
+
+	libwacom_parse_key_codes(device, keyfile);
+}
+
+
 static int
 styli_id_sort(gconstpointer pa, gconstpointer pb)
 {
@@ -829,6 +898,7 @@ libwacom_parse_tablet_keyfile(WacomDeviceDatabase *db,
 
 	libwacom_parse_features(device, keyfile);
 	libwacom_parse_buttons(device, keyfile);
+	libwacom_parse_keys(device, keyfile);
 
 	success = TRUE;
 
diff --git a/libwacom/libwacom.c b/libwacom/libwacom.c
index 27e6eadd4..92155994c 100644
--- a/libwacom/libwacom.c
+++ b/libwacom/libwacom.c
@@ -379,6 +379,10 @@ libwacom_copy(const WacomDevice *device)
 		WacomButton *b = g_memdup2(a, sizeof(WacomButton));
 		g_hash_table_insert(d->buttons, k, b);
 	}
+
+	d->num_keycodes = device->num_keycodes;
+	memcpy(d->keycodes, device->keycodes, sizeof(device->keycodes));
+
 	return d;
 }
 
@@ -1120,6 +1124,12 @@ libwacom_get_num_buttons(const WacomDevice *device)
 	return g_hash_table_size(device->buttons);
 }
 
+LIBWACOM_EXPORT int
+libwacom_get_num_keys(const WacomDevice *device)
+{
+	return device->num_keycodes;
+}
+
 LIBWACOM_EXPORT const int *
 libwacom_get_supported_styli(const WacomDevice *device, int *num_styli)
 {
diff --git a/libwacom/libwacom.h b/libwacom/libwacom.h
index cafed6402..389681d2b 100644
--- a/libwacom/libwacom.h
+++ b/libwacom/libwacom.h
@@ -594,6 +594,16 @@ int libwacom_has_touch(const WacomDevice *device);
  */
 int libwacom_get_num_buttons(const WacomDevice *device);
 
+/**
+ * Tablet keys indices are numbered from zero
+ *
+ * @param device The tablet to query
+ * @return The number of keys on the tablet
+ *
+ * @ingroup devices
+ */
+int libwacom_get_num_keys(const WacomDevice *device);
+
 /**
  * @param device The tablet to query
  * @param num_styli Return location for the number of listed styli
diff --git a/libwacom/libwacom.sym b/libwacom/libwacom.sym
index e517f2de7..76ed06921 100644
--- a/libwacom/libwacom.sym
+++ b/libwacom/libwacom.sym
@@ -68,3 +68,7 @@ global:
 local:
         *;
 };
+
+LIBWACOM_2.9 {
+    libwacom_get_num_keys;
+} LIBWACOM_2.0;
diff --git a/libwacom/libwacomint.h b/libwacom/libwacomint.h
index e1af83845..537afdb48 100644
--- a/libwacom/libwacomint.h
+++ b/libwacom/libwacomint.h
@@ -67,6 +67,11 @@ typedef struct _WacomButton {
 	int code;
 } WacomButton;
 
+typedef struct _WacomKeycode {
+	unsigned int type;
+	unsigned int code;
+} WacomKeycode;
+
 /* WARNING: When adding new members to this struct
  * make sure to update libwacom_copy() and
  * libwacom_print_device_description() ! */
@@ -92,6 +97,8 @@ struct _WacomDevice {
 
 	GArray *styli;
 	GHashTable *buttons; /* 'A' : WacomButton */
+	WacomKeycode keycodes[32];
+	size_t num_keycodes;
 
 	GArray *status_leds;
 
diff --git a/test/test-load.c b/test/test-load.c
index 10938b022..abb80117a 100644
--- a/test/test-load.c
+++ b/test/test-load.c
@@ -226,6 +226,16 @@ test_cintiq13hd(struct fixture *f, gconstpointer user_data)
 	libwacom_destroy(device);
 }
 
+static void
+test_cintiqpro13(struct fixture *f, gconstpointer user_data)
+{
+	WacomDevice *device = libwacom_new_from_name(f->db, "Wacom Cintiq Pro 13", NULL);
+	g_assert_nonnull(device);
+	g_assert_cmpint(libwacom_get_num_keys(device), ==, 5);
+
+	libwacom_destroy(device);
+}
+
 static void
 test_bamboopen(struct fixture *f, gconstpointer user_data)
 {
@@ -294,6 +304,9 @@ int main(int argc, char **argv)
 	g_test_add("/load/056a:0304", struct fixture, NULL,
 		   fixture_setup, test_cintiq13hd,
 		   fixture_teardown);
+	g_test_add("/load/056a:034f", struct fixture, NULL,
+		   fixture_setup, test_cintiqpro13,
+		   fixture_teardown);
 	g_test_add("/load/056a:0065", struct fixture, NULL,
 		   fixture_setup, test_bamboopen,
 		   fixture_teardown);
diff --git a/tools/libwacom-update-db.py b/tools/libwacom-update-db.py
index e30c88c99..c503c3381 100755
--- a/tools/libwacom-update-db.py
+++ b/tools/libwacom-update-db.py
@@ -147,7 +147,7 @@ def _load(self, path):
                         )
                 except KeyError:
                     pass
-                t.has_pad = config.has_section("Buttons")
+                t.has_pad = any(config.has_section(s) for s in ["Buttons", "Keys"])
                 yield t