diff --git a/system/kbd/CMakeLists.txt b/system/kbd/CMakeLists.txt new file mode 100644 index 000000000..8ee13e65b --- /dev/null +++ b/system/kbd/CMakeLists.txt @@ -0,0 +1,35 @@ +# ############################################################################## +# apps/system/kbd/CMakeLists.txt +# +# SPDX-License-Identifier: Apache-2.0 +# +# Licensed to the Apache Software Foundation (ASF) under one or more contributor +# license agreements. See the NOTICE file distributed with this work for +# additional information regarding copyright ownership. The ASF licenses this +# file to you under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy of +# the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations under +# the License. +# +# ############################################################################## + +if(CONFIG_SYSTEM_KBD) + nuttx_add_application( + NAME + ${CONFIG_SYSTEM_KBD_PROGNAME} + PRIORITY + ${CONFIG_SYSTEM_KBD_PRIORITY} + STACKSIZE + ${CONFIG_SYSTEM_KBD_STACKSIZE} + MODULE + ${CONFIG_SYSTEM_KBD} + SRCS + kbd_main.c) +endif() diff --git a/system/kbd/Kconfig b/system/kbd/Kconfig new file mode 100644 index 000000000..d1030ab09 --- /dev/null +++ b/system/kbd/Kconfig @@ -0,0 +1,38 @@ +# +# For a description of the syntax of this configuration file, +# see the file kconfig-language.txt in the NuttX tools repository. +# + +config SYSTEM_KBD + tristate "Keyboard dump" + default n + depends on INPUT_KEYBOARD + ---help--- + Dump what a keyboard reports. This reads any keyboard registered + with keyboard_register(), whatever the hardware behind it is, so it + is the tool to reach for when bringing up a new keyboard. + + Replaces the hidkbd and keyboard examples, which did the same thing + for one kind of keyboard each. + +if SYSTEM_KBD + +config SYSTEM_KBD_PROGNAME + string "Program name" + default "kbd" + +config SYSTEM_KBD_PRIORITY + int "Task priority" + default 100 + +config SYSTEM_KBD_STACKSIZE + int "Task stack size" + default DEFAULT_TASK_STACKSIZE + +config SYSTEM_KBD_DEVPATH + string "Keyboard device path" + default "/dev/kbd0" + ---help--- + The keyboard to read when none is named on the command line. + +endif diff --git a/system/kbd/Make.defs b/system/kbd/Make.defs new file mode 100644 index 000000000..f80780936 --- /dev/null +++ b/system/kbd/Make.defs @@ -0,0 +1,25 @@ +############################################################################ +# apps/system/kbd/Make.defs +# +# SPDX-License-Identifier: Apache-2.0 +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. The +# ASF licenses this file to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance with the +# License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +############################################################################ + +ifneq ($(CONFIG_SYSTEM_KBD),) +CONFIGURED_APPS += $(APPDIR)/system/kbd +endif diff --git a/system/kbd/Makefile b/system/kbd/Makefile new file mode 100644 index 000000000..97c5dad19 --- /dev/null +++ b/system/kbd/Makefile @@ -0,0 +1,32 @@ +############################################################################ +# apps/system/kbd/Makefile +# +# SPDX-License-Identifier: Apache-2.0 +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. The +# ASF licenses this file to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance with the +# License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +############################################################################ + +include $(APPDIR)/Make.defs + +PROGNAME = $(CONFIG_SYSTEM_KBD_PROGNAME) +PRIORITY = $(CONFIG_SYSTEM_KBD_PRIORITY) +STACKSIZE = $(CONFIG_SYSTEM_KBD_STACKSIZE) +MODULE = $(CONFIG_SYSTEM_KBD) + +MAINSRC = kbd_main.c + +include $(APPDIR)/Application.mk diff --git a/system/kbd/kbd_main.c b/system/kbd/kbd_main.c new file mode 100644 index 000000000..a736dd85c --- /dev/null +++ b/system/kbd/kbd_main.c @@ -0,0 +1,265 @@ +/**************************************************************************** + * apps/system/kbd/kbd_main.c + * + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/* Dump what a keyboard reports. + * + * Every keyboard registered with keyboard_register() is read the same way, + * whatever the hardware behind it is: a USB HID keyboard, a matrix, the + * simulator, virtio. So this works with all of them, and it is the place + * to look when bringing up a new one. + * + * The device delivers struct keyboard_event_s events unless the kernel was + * built with INPUT_KEYBOARD_BYTESTREAM, in which case it delivers the byte + * stream that the keyboard codec defines. This follows that setting rather + * than having a switch of its own. + */ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#ifdef CONFIG_INPUT_KEYBOARD_BYTESTREAM +# include +# include +#endif + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define KBD_READ_SIZE 64 + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: kbd_typename + ****************************************************************************/ + +static FAR const char *kbd_typename(uint32_t type) +{ + switch (type) + { + case KEYBOARD_PRESS: + return "press"; + + case KEYBOARD_RELEASE: + return "release"; + + case KEYBOARD_SPECPRESS: + return "specpress"; + + case KEYBOARD_SPECREL: + return "specrel"; + + default: + return "unknown"; + } +} + +/**************************************************************************** + * Name: kbd_show + * + * Description: + * Print one key. A normal key carries a character, a special key carries + * a value from enum kbd_keycode_e, and the type is what says which. + * + ****************************************************************************/ + +static void kbd_show(uint32_t code, uint32_t type) +{ + if (type == KEYBOARD_PRESS || type == KEYBOARD_RELEASE) + { + printf("%-9s code %3" PRIu32 " '%c'\n", kbd_typename(type), code, + isprint(code) ? (int)code : '.'); + } + else + { + printf("%-9s keycode %" PRIu32 "\n", kbd_typename(type), code); + } + + fflush(stdout); +} + +/**************************************************************************** + * Name: kbd_dump + * + * Description: + * Print everything in one read. + * + * Returned Value: + * The number of keys printed. + * + ****************************************************************************/ + +#ifdef CONFIG_INPUT_KEYBOARD_BYTESTREAM +static size_t kbd_dump(FAR char *buffer, size_t nbytes) +{ + struct lib_meminstream_s stream; + struct kbd_getstate_s state; + uint8_t ch; + size_t nkeys = 0; + int ret; + + lib_meminstream(&stream, buffer, nbytes); + memset(&state, 0, sizeof(state)); + + for (; ; ) + { + ret = kbd_decode(&stream.common, &state, &ch); + if (ret == KBD_ERROR) + { + break; + } + + kbd_show(ch, ret); + nkeys++; + } + + return nkeys; +} +#else +static size_t kbd_dump(FAR char *buffer, size_t nbytes) +{ + FAR struct keyboard_event_s *key = (FAR struct keyboard_event_s *)buffer; + size_t nkeys = 0; + + if ((nbytes % sizeof(struct keyboard_event_s)) != 0) + { + fprintf(stderr, "kbd: short read of %zu bytes, ignoring\n", nbytes); + return 0; + } + + while (nbytes >= sizeof(struct keyboard_event_s)) + { + kbd_show(key->code, key->type); + + nbytes -= sizeof(struct keyboard_event_s); + key++; + nkeys++; + } + + return nkeys; +} +#endif + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: main + ****************************************************************************/ + +int main(int argc, FAR char *argv[]) +{ + FAR const char *devpath = CONFIG_SYSTEM_KBD_DEVPATH; + char buffer[KBD_READ_SIZE]; + size_t nkeys = 0; + size_t limit = 0; + ssize_t nbytes; + int fd; + + if (argc > 1) + { + devpath = argv[1]; + } + + if (argc > 2) + { + limit = strtoul(argv[2], NULL, 10); + } + + /* Wait for the device. A USB keyboard appears when it is plugged in, so + * this is the normal way to start rather than an error path. + */ + + for (; ; ) + { + fd = open(devpath, O_RDONLY); + if (fd >= 0) + { + break; + } + + printf("kbd: waiting for %s: %d\n", devpath, errno); + fflush(stdout); + sleep(3); + } + + printf("kbd: reading %s, %s\n", devpath, +#ifdef CONFIG_INPUT_KEYBOARD_BYTESTREAM + "byte stream" +#else + "keyboard events" +#endif + ); + fflush(stdout); + + for (; ; ) + { + nbytes = read(fd, buffer, sizeof(buffer)); + if (nbytes < 0) + { + if (errno == EINTR) + { + continue; + } + + fprintf(stderr, "kbd: read %s failed: %d\n", devpath, errno); + break; + } + else if (nbytes == 0) + { + /* The keyboard is gone */ + + break; + } + + nkeys += kbd_dump(buffer, nbytes); + + if (limit > 0 && nkeys >= limit) + { + break; + } + } + + close(fd); + printf("kbd: %zu keys\n", nkeys); + return EXIT_SUCCESS; +}