If your inclination is to combine streams every time you need to ensure that event ordering is maintained, you could end up with a lot of streams being combined, and thus a traditional event queue. Next thing you know, you might want to be able to inject application-created events into that queue, just to preserve ordering of something else relative to the incoming events. If the system won’t let you add to the main event queue, you might create your own queue in your application (or supporting library) just to be able to mix system events with your own events. Then you end up with a lot of event types, and switch statements in dispatching code (like Qt has a good number of, for example), and the extra queuing creates delays. So now and then I take to pondering, what could be more elegant if that pattern is to be avoided?
One cause of the ordering problem is that separate processes handle incoming events from their respective devices, right? e.g. kbdfs is independent, so you can’t be sure that if you are trying to read from multiple devices, that you will get the events in the same order that the user manipulates the devices. If there were just one process to handle all input devices (call it inputfs), I would think it could continue to serve up separate streams on separate files, and still enforce ordering as long as the read operation is blocking. I.e. if you opened both the mouse and the keyboard, and a modifier is pressed, you need to read the keyboard file to get the changed modifiers before you are allowed to read the next mouse event. Are there some bad deadlock cases with such an approach? (I didn’t try, it’s just an idea.) But input events should have timestamps anyway, generated as close-to-the-hardware as possible. (e.g. in an interrupt handler?) That could provide an alternative mechanism to reorder events, if there is no other way to guarantee that they will be emitted to the files in the correct order. Then if you read events in the wrong order, at least you can detect that it’s in the wrong order, and it will be obvious how to fix that bug. I don’t like the Plan 9 tendency to put space-separated sequences of data values in files. The knowledge of what those fields mean is out-of-line, so you rely on your memory when reading it manually, and changing the schema is also hard. csv at least has a header line to label the fields. This is also why things like xml, json, messagepack and all the others were invented (mostly ugly) https://en.wikipedia.org/wiki/Comparison_of_data-serialization_formats . So now you wonder how to add keyboard modifier state to the mouse events, and are afraid to add another field, so you come up with hacks like higher-numbered mouse buttons or extra bits. If the fields were labeled in the first place, somehow, it would be extensible. But making every line into a dictionary is too verbose. Well, maybe put the schema into a separate file then, and expect libraries to use it to populate their event structs? If the struct is missing some fields that were added recently, then you are just missing the new info, but the new fields do not get in the way of populating the old struct. If the struct has new fields that aren’t available in practice, use standard values to indicate that they are uninitialized (empty string, -1, NaN, ...). Next evolutionary step is maybe to choose a binary format that is easily tokenized (maybe add a length to each field, so that arbitrary lengths are ok). Maybe use small numbers for the field labels, and put the schema (table mapping the small numbers to their meanings) elsewhere. (Maybe in the first record that you read from the file, as in csv.) Probably some of the old standards already do it that way. I once invented a format like that myself, for serializing arbitrary hierarchical data (like a binary XML) and compacting the element IDs into small numbers, but I suspect it’s redundant by now. Anyway, it’s a form of unaligned bytewise serialization. So I figured I could do better. Next improvement is to have a standard way to represent a vector in memory (including a length field), and make the event file provide those vectors in little-endian layout so that each event can be copied into process memory and used directly. Eliminate deserialization and parsing completely. The “schema” would just be another vector containing the field labels. But then you need fixed field lengths, which creates limits (e.g. it could be a vector of 64-bit values, with NaN-boxing to distinguish types, leaving you 51 bits for all non-double types; if strings are supported as a type in a vector, then the labels in the “schema" can’t be longer than 6 ascii characters, or 8 6-bit characters, or 10 5-bit characters, or else strings have to be stored separately in a hash table or something). If a mouse event comes in this form (a vector of doubles and ints), and you want to find the “x” value, you first search for “x” in the schema vector, which gives you the offset. Every event from then on can be expected to have “x” at the same offset. But a future version of inputfs is free to change the schema, without breaking applications. Adding keyboard modifiers to the mouse events would be easy then (if you haven’t solved the event timing problem some other way). To read it by hand on the command line, you need a different tool than cat or tail, but it can read all such binary-vector files, which ought to have many other uses. That’s something I’m working on in a different context. If files in /dev are going to change, we ought to make it future-proof this time. Support all possible input devices, even those that haven’t been invented yet. For now though, there’s multi-touch (touchscreens and touchpads), jog/shuttle controls and other kinds of encoders, joysticks, tablet/stylus, VR controllers, etc. Shoehorning all of that into hacks that fit the old schemas for keyboard and mouse would be really limiting (despite the excuses that are made about that). They are different devices for a reason. In general, there could be many devices in use at the same time. To me it seems natural to continue with separate streams for each, rather than interleaving the events in one file. > On Oct 1, 2024, at 3:56 AM, o...@eigenstate.org wrote: > > This is a problem that can happen with any keyboard input; > if I press 'A' and click, this problem can also happen. > > Fixing this would probably need merging both event streams > into one /dev/input or similar. > > Quoth Alyssa M via 9fans <9fans@9fans.net>: >> If mouse click events are queued and the keyboard modifier state changes are >> not (or are queued separately), they can get out of step. By the time the >> program receives a mouse click event, the keyboard may be unshifted again. >> This could happen if a program is late processing mouse input. ------------------------------------------ 9fans: 9fans Permalink: https://9fans.topicbox.com/groups/9fans/T1dee2a7aea3f7fa3-M682112905f99c35a5eea9bce Delivery options: https://9fans.topicbox.com/groups/9fans/subscription