|
| 1 | +========================= |
| 2 | +CNxConsole Keyboard Input |
| 3 | +========================= |
| 4 | + |
| 5 | +**Players** |
| 6 | + |
| 7 | +Let's look at the major players in the keyboard data transfer. This is much more |
| 8 | +complex than you might initially think: |
| 9 | + |
| 10 | +**Special Drivers** |
| 11 | +NxConsole Device. The NX console input comes through a special device driver that |
| 12 | +is registered at ``/dev/nxcon0`` as part of early initialization. |
| 13 | + |
| 14 | +**Kernel Threads** |
| 15 | + |
| 16 | +* **NX Server Thread** The NX Server is the graphics server command. It receives |
| 17 | + messages from various sources, performs graphics actions, and forwards graphic |
| 18 | + event messages to the correct window. Most of the time, the NX Server Thread was |
| 19 | + waiting on a message queue to receive the next graphics event. |
| 20 | + |
| 21 | +* **NxConsole Threads** Each NxConsole has a thread that was started when each |
| 22 | + ``NxWM::CNxConsole`` instance was created by NxWM. Each ``NxWM::CNxConsole`` |
| 23 | + thread opens the NxConsole driver at ``/dev/nxcon0`` and redirects stdin, |
| 24 | + stdout, and stderr to/from that special device. Normally, the ``NxWM::CNxConsole`` |
| 25 | + thread is stopped, just waiting on read for keyboard input to complete. |
| 26 | + |
| 27 | +**Application Threads** |
| 28 | + |
| 29 | +* **NxWidgets Window Event Handler Thread** ``CNxServer::listener()`` is an |
| 30 | + application thread started by NxWidgets each time a new window is opened. |
| 31 | + It receives window messages from the NX server and dispatches the messages |
| 32 | + accordingly. |
| 33 | + |
| 34 | +* **Keyboard Listener Thread** ``CKeyboard::listener()`` is an application thread |
| 35 | + that is started by NxWM. It just listens for keyboard input and forwards it through |
| 36 | + the graphics routing system. |
| 37 | + |
| 38 | +Now here is the sequence of events to get keyboard input from the stdin device to |
| 39 | +the correct NxConsole. |
| 40 | + |
| 41 | +#. Application Space / NxWidgets Window Event Handler Thread |
| 42 | + Let's start with the initial state of the NX Server Thread. Initially, it will |
| 43 | + just want for messages from the NX Server. |
| 44 | + |
| 45 | + * ``NxWidgets/libnxwidgets/src/cnxserver.cxx`` |
| 46 | + ``CNxServer::listener()`` is it window listener thread. It just calls |
| 47 | + ``nx_eventhandler()`` to receive and process server events. There is one |
| 48 | + such listener thread per window. |
| 49 | + |
| 50 | + * ``nuttx/libnx/nxwm/nx_eventhandler`` |
| 51 | + ``nx_eventhandler()`` waits to receive a message from the NX server. Each |
| 52 | + window has its own message queue; each window instance has its own |
| 53 | + ``nx_eventhandler()`` waiting for messages. |
| 54 | + |
| 55 | +#. Application Space / Keyboard Listener Thread |
| 56 | + |
| 57 | + Here are the immediate events that happen when the keyboard data is entered. |
| 58 | + The Keyboard Listener Thread wakes up and forwards the Keyboard data to the |
| 59 | + the NX Server. Only the NX Server knows which window should get the keyboard input. |
| 60 | + |
| 61 | + * ``NxWidgets\nxwm\src\ckeyboard.cxx`` |
| 62 | + ``CKeyboard::listener()`` is a tiny thread that is started by NxWM that just |
| 63 | + listens for keyboard input. It opens the keyboard device and waits on a ``read()`` |
| 64 | + from the keyboard device to receive the next keyboard input. When data is |
| 65 | + returned by reading from the keyboard device, ``CKeyboard::listener()`` |
| 66 | + calls ``nx_kbdin()`` |
| 67 | + |
| 68 | + * ``nuttx\libnx\nxmu\nx_kbdin.c`` |
| 69 | + This library function just hides the NX server messaging implementation. |
| 70 | + It sends the ``NX_SVRMSG_KBDIN`` to the NX server thread. |
| 71 | + |
| 72 | +#. Kernel Space / NX Server |
| 73 | + |
| 74 | + The NX Server wakes up, receives the keyboard message, and forwards it to the |
| 75 | + appropriate window. |
| 76 | + |
| 77 | + * ``nuttx/graphics/nxmu/nxmu/nxmu_server.c`` |
| 78 | + The receipt of the ``NX_SVRMSG_KBDIN`` message wakes up the NX server |
| 79 | + thread. The NX server thread decodes the message and calls ``nxmu_kbdin()``. |
| 80 | + |
| 81 | + * ``nuttx/graphics/nxconsole/nxmu_kbdin.c`` |
| 82 | + ``nxmu_kbdin()`` simply sends the ``NX_CLIMSG_KBDIN`` to the appropriate |
| 83 | + windows client via the client message queue associated with the window. |
| 84 | + |
| 85 | +#. Application Space / NxWidgets Window Event Handler Thread |
| 86 | + |
| 87 | + The Windows client wakes up when the keyboard message is received. It forwards |
| 88 | + the keyboard data to ``/dev/nxcon0/`` so that is can be available to the |
| 89 | + NxConsole window. |
| 90 | + |
| 91 | + * ``nuttx/libnx/nxwm/nx_eventhandler`` |
| 92 | + The ``nx_eventhandler()`` logic running in the ``CNxServer::listener()`` |
| 93 | + thread receives the ``NX_CLIMSG_KBDIN`` message and dispatches it to the |
| 94 | + kbdin callback method. In this case that callback method maps to |
| 95 | + ``CCallback::newKeyboardEvent()``. |
| 96 | + |
| 97 | + * ``NxWidgets/libnxwidgets/src/ccallback.cxx`` |
| 98 | + For normal keyboard input, ``CCallback::newKeyboardEvent()`` directs the |
| 99 | + Keyboard to the widget with focus via the ``CWidgetControl::newKeyboardEvent()`` |
| 100 | + method. But the story is different for the NxConsole window. This case, |
| 101 | + ``CCallback::newKeyboardEvent()``, calls ``nxcon_kbdin()``. |
| 102 | + |
| 103 | + * ``nuttx/graphics/nxconsole/nxcon_kbdin.c`` |
| 104 | + ``nxcon_kbdin()`` adds the keyboard data to a circular buffer and wakes up |
| 105 | + any reads on the ``/dev/nxcon0`` input device. |
| 106 | + |
| 107 | + |
| 108 | + NOTE: Here is a violation of the Application and Kernel Space boundaries. |
| 109 | + ``nxcon_kbdin.c`` built into Kernel Space but it is called from Application |
| 110 | + Space. The solution is to (1) move ``nxcon_kbdin()`` to ``libnx/`` and (2) it |
| 111 | + should then communicate with the ``/dev/nxcon9`` driver via ioctl calls. |
| 112 | + This will become a problem some day. |
| 113 | + |
| 114 | +#. Kernel Space / NxConsole Thread |
| 115 | + |
| 116 | + Finally, |
| 117 | + * ``nuttx/graphics/nxconsole/nxcon_kbdin.c`` |
| 118 | + The receipt and enqueuing of keyboard data by ``nxcon_kbdin()`` wakes up |
| 119 | + any threads waiting in the ``nxcon_read()`` method. This is how the |
| 120 | + NxConsole gets its keyboard input. |
| 121 | + |
| 122 | + |
| 123 | +**Mouse Input** |
| 124 | +Almost everything said here applies to mouse/touchscreen input as well. If we |
| 125 | +were to replace the names keyboard to mouse, kbdin to mousein, etc. you have a |
| 126 | +pretty good description of how mouse/touchscreen input works. |
| 127 | + |
| 128 | +The mouse/touchscreen input is a little simpler, however: The main simplication |
| 129 | +is that the additional complexities of the NxConsole and its special input device |
| 130 | +do not apply. Mouse/touchscreen inut as always steered to widgets when the |
| 131 | +callback is received in ``CCallback::newMouseEvent`` by an unconditional call to |
| 132 | +``CWidgetControl::newMouseEvent``. There is a "fork in the road" at the |
| 133 | +corresponding point in the logic of ``CCallback::newKeyboardEvent`` |
0 commit comments