key down / up events to wimp?
Tim Rowledge (1742) 170 posts |
In my work to support Scratch nicely on RISC OS – since that seems like a good way to get a fair bit more educational interest – I find that something which has merely irritated me for a couple of decades is now an actual Serious Problem (insert non-smiling cat here)that I really need to address. The low-level system happily reports key events as up/down (and nicely includes the mouse buttons, or at least used to) but the wimp events only provide a “this character was entered from the keyboard” event. I’ve never really understood why such a restrictive view was taken for key presses; after all for any musical keyboard type app it would make much more sense to have the down/ups separately. And indeed for Scratch I really need them. Has anyone ever written, seen, used, heard of or otherwise come into contact with a module that might provide the two separately? I’m already using DeepKeys to try to keep track of assorted modifier keys – I don’t suppose it can report up/down and I silly haven’t found a doc that says so? Do we have access to the DeepKeys source and therefore have a chance to enhance it? |
Michael Foot (522) 26 posts |
I’ve been (slowly) working on a version of BeebIt that runs in the WIMP and for that I needed key up/down events to be processed as well. I have put together a rudimentary module to do this which can be used by multiple applicatons at the same time. I’m happy to let you see the source code for this but you would need to do some more work on it and get a SWI number registered for it to be useful to you. Michael. |
nemo (145) 2546 posts |
Well I do. Cos I wrote it. Key transitions haven’t traditionally been messaged because of the obvious avalanche problems – any latency (eg loading a large file) could result in hundreds of messages getting queued, as would leaning on the keyboard. Once you have a few applications trying to use the heavyweight Wimp message queueing system for something as lightweight as key transitions things will start to get very clunky. Or to put it another way, it’s a very bad idea indeed. What you want is a module (or some code outside application space anyway) sitting on KeyV and maintaining some mapping of the keyboard. That’s what my DeepKeys and FixUpDown modules do. When that state changes that code changes the poll word of your application which, when it therefore gets a null event, queries the module (or code, or map) and gets all the current state. However, you then mentioned
No, no, no. You cannot rely on Wimp messages for real-time work. A musical program (that presumably is emitting sounds or recording note events) cannot operate reliably by wimp polling – there’s too much latency and unpredictable interruptions. Your Wimp poll bit is the user interface, but real-time functionality such as responding to key transitions MUST be done immediately, and KeyV is probably the right hook to use. |
Tim Rowledge (1742) 170 posts |
Hi Nemo, well I’m glad someone is still responsible for DeepKeys because Squeak relies on it. (As an aside, is there an official location from which to download it? Any updates since dinosaurs roamed the earth? I have v 2.06 circa 2003) I understand what you are saying about the issues of trying to realtime event handling; been there, done that, wrote an operating system. For many – and in particular my – needs, it isn’t hard. As in hard realtime. Typically Squeak checks wimp_poll a thousand or so times a second so it’s not going to miss an event by very much in the typical case. If it misses because some other app is busy, well tough luck mr user, your machine is working hard. That happens quite a bit on unixes. A very long time ago an ancestor of Squeak ran on Arthur and I did indeed use KeyV etc directly. It was in some ways much nicer than living in the desktop when it came along. I could happily use a module that hooked back into KeyV so long as it could easily work with other parts of the OS to do key mapping for language etc. |
Tim Rowledge (1742) 170 posts |
Oh, and thank you Michael, I’d very much like to see your code sometime. |
nemo (145) 2546 posts |
There will be. I’m in the process of fiddling with my domains and I’ve started releasing things here. I’ll get DeepKeys there soon, but I’m going to be in Barcelona for a few days so it won’t be before the end of next week.
There is a 2.07 from 2003, the source says “Now includes MouseUp functionality” but I can’t remember right now what that means. :-) No updates since then because nobody asked for anything. As for key transitions, it is similar to keypresses – individual messages are inefficient (or rather cause inefficient handling). In some editors I’ve written I concatenate cursor key keypresses and then act on them in bulk (ie ‘down’ by 12, rather than doing the ‘down’ functionality 12 times). So I’d still recommend a pull over a push interface, as you could then deal with bulk transitions efficiently. |
Tim Rowledge (1742) 170 posts |
I look forward to a new DeepKeys sometime. I agree with your assessment about efficiency in some cases but right now to support Scratch (which really is quite important to RaspberryPi foundation and possibly to a future for RISC OS) I need something similar to what we get from both X & fbdev on linux, from OSX and even windows (even frikkin windows!) which is to say some kind of event for a key-down and another for a key-up. Windows & OSX seem to do a triplet of down (with fairly raw key data) + key press (with processed key values) + up (with raw data again). The linux fbdev provides just down & up so far as I can see. I don’t mind either way. One thing I am puzzled about is how to make whatever solution arises work with the normal key presses; would I ignore those events, not poll for them at all, or would some extension of DeepKeys be able to do magic and make ‘normal’ events with the extra detail I need? I’m guessing not the last since it would probably involve double key presses for non-aware code. If we had a module that watched KeyV and queued suitable data, how would we handle multiple clients? What should happen when a different window (or a different app) gets focus? |
nemo (145) 2546 posts |
Apologies for tardiness, I have adopted Spanish practices (by which I mean I am in Spain). DeepKeys already delivers key-down events for those transitions that result in a keypress being buffered. It would be bad practice though for Deepkeys to try to guess which keys do and don’t generate key presses, so it would have to synchronise its transition and buffering code such that it can buffer a special key code for ‘did not cause a keypress’ and another for ‘key up’. Deepkey’s filter (which currently adds the internal key numbers to keypress polls) could then mutate those new keypress events into some other event. This would mean one couldn’t filter those out with the poll filter (because they’re really keypress events), so it is possible some apps may fall over. Unlikely, but possible. The alternative, of delivering ‘new’ key codes all the time would definitely cause some apps to go wrong, probably spectacularly. |
Tim Rowledge (1742) 170 posts |
I hope you’re having fun in Spain. Does the rain really fall mainly on the plain? Since we now have access to the source it might be possible to make better ‘guesses’ about what is happening, or even I suppose completely replace the code and make it do more helpful things. You’ve also reminded me how annoying it is that only some key presses provide events – why can’t I get most alt-keys, for example? Maybe we need to have a different input route for extended key press events. Surely there’s some flag bits left for wimp-poll and an opportunity for a new event type? |
Michael Foot (522) 26 posts |
Hi Tim, I’ve uploaded my code here: http://homepages.paradise.net.nz/mjfoot/riscos/KeyBuffer.zip It’s very much work in progress but may be of some use to you. If you use it, please send any changes back to me. Thanks. |
nemo (145) 2546 posts |
Sadly (for me) I’m back in the snowy UK. I’ve been tweeting pictures of tapas for four days. And no, it didn’t rain at all – 21°C typical. :-/
DeepKeys doesn’t guess, it reports exactly how a keypress was generated, including the state of nine modifier keys and the key that caused a code to be buffered. And I’ve always had access to the source!
If you mean the keyboard driver, well that’s a separate (and replaceable) component (and I wrote my own for the MMK keyboard Cerilica sold) so DeepKeys should mind its own business in that regard – it can augment what the keyboard driver does, but it shouldn’t change it.
It is the keyboard driver’s role to convert key transitions into buffered keypresses, and it is important not to impose one’s own familiar input method on others who may have very different requirements. The keyboard driver you are using has various alt-keypresses mapped to Latin1 characters. My RISC OS and Windows keyboard drivers implement 14 accents (eg à ć ő ê š ï ō å ñ ç ę ģ ż đ) and lots more useful characters, and a Japanese keyboard driver is very different again. This is why there is a distinction between key transitions and keyboard buffering. DeepKeys allows a much greater range of codes to be buffered, so it is easy to choose codes to represent those key transitions that (it turns out) did not buffer a keypress (though may have changed the internal state of the keyboard driver – like dead accents). Ensuring that these new keypress codes don’t confuse programs is the tricky bit, which is why I proposed mutating those keypress events into something such programs would be more likely to ignore. |
Tim Rowledge (1742) 170 posts |
Apologies for confusion; by ‘access to the source’ I was referring to the RISC OS source as opposed to your module. Though for all I know you might have had RISC OS source as well! As must be clear by now I don’t know how the system is handling key presses at all so do please forgive any misconceptions. I’d like to be able to get nice clear information, preferably via the ordinary channels but using a poll word etc would do, about which keys have been pressed and which released, including all the modifiers you have deep keys handling, including all keys even when there is no clear character (like say ctl-shift-alt-X). Somewhere there is code that watches the key events and ends up with them being made into wimp events, doing translation from raw key code to characters and making sure they are tagged to the relevant window. Can I have something similar, somehow? Pretty please with chocolate on top? |
Rick Murray (539) 13840 posts |
My MoreKeys module looks for Ctrl-Alt-keypress. If it spots one (with some exceptions) it will claim the event and suppress the key. The keypress will then be stuffed into a PollWord which the front end will pick up on and display the selector window for related accented keys. Are you looking for something like this? Maybe not the key suppress, but the key detection? I hook into Event 11 (not KeyV as that isn’t present in older versions of RISC OS); from there (or KeyV) it is not difficult to record key transitions to pass on to the foreground application. The only thing that concerns me is whether or not said transitions are relevant to your application. For me, it had a specific purpose so the back-end module does the filtering. For you, it would seem more general purpose so how do you plan on knowing which transitions matter to you and which are for other applications? Will you be tracking Gain_Caret / Lose_Caret ? FWIW if I had some sort of write access to ROOL’s codebase, I’d licence MoreKeys as EUPL and drop a copy in there so it can add to the available functionality of the platform. It’s got to be better than stuck on some backwater website like HeyRick… ☺ |
nemo (145) 2546 posts |
Tim confessed:
Some hardware driver (USB/PS2/Acorn/other) detects switch transitions or input codes, maps them to “key numbers” and issues key transitions on KeyV. The kernel (UtilityModule actually) takes those transitions and feeds them (via EventV,11 if enabled) to the currently selected Key Handler (OS_InstallKeyHandler) – which I have referred to as the keyboard driver. The Key Handler converts many of those transitions into “internal key numbers” (the old Beeb INKEY numbers, which are different to the Arc’s “key numbers”) and keyboard buffer codes. It has to pay attention to the configured country, keyboard and alphabet and in later OSes additional options such as ‘PC delete’. It also has to maintain the state of the shift keys so it can produce upper or lower case as appropriate. It maps key transitions to alphabetic keypresses, mouse buttons, modifiers, dead accents and various configuration key combinations such as the dialling code country selection via the numeric keypad. Handling function keys, tab and the cursor keys requires honouring various OS_Byte settings, which the Wimp for example uses to modify the codes that are buffered – outside the desktop the function keys act as *Key macros, inside the desktop they just produce single keypresses.
As I say, that should be fairly straightforward – the non-keypress transitions being delivered as a new event. Rick then got into trouble by stating:
That is absolutely the wrong thing to do. You are preventing the key handler from doing its job and you cannot know what functionality you are breaking – every keyboard driver can be different. For example, for Cerilica’s MMK keyboard driver (which I use even without that keyboard) you have stopped these characters being available “”–—øت’−• and have killed the following dead accents: hungarumlaut, macron, breve, caron, ogonek, dot and slash. >:-[ What effect does it have on a Chinese or Japanese IME? How about Hebrew? Arabic? This is not the right approach at all.
This is why I have proposed sending such transitions to the keyboard buffer so they will always go to the right application. Care will have to be taken that certain OS_Bytes and OS_ReadLine still do the right thing though.
It is probably best that those who modify the codebase fully understand the ramifications of their changes, especially outside Little England. |
Rick Murray (539) 13840 posts |
It is a means to an end for providing additional keypresses that the native keyboard is unable to provide. The logically better option would be to provide a better keyboard handler – however MoreKeys is able to respond to changes in configured language that may be more problematic for a keyboard handler. Plus, it is configurable, which is more than can be said for the keyboard handler. If you want additional key options (smart quotes etc) you need to load an extension to mess with what keypresses are available… so this approach is hardly unprecedented.
They are available via MoreKeys :-) Seriously – if it doesn’t work with your setup, don’t use it!
Point me at a Japanese IME, then we’ll talk. I have some code to intercept regular keypresses and output Katagana and Hiragana according to key (ASDFG → チトシハキ, etc).
Feel free to come up with something better. I’m working on making something that works with what we have now and not some (imaginary?) future incarnation with Japanese, Chinese, Arabic, and Hebrew.
I only trap a keypress with Ctrl and Alt. Nothing else. Other stuff is passed on as normal. The point is to complement the current system, not entirely break it. Fixing your keyboard would be a simple thing to do – MoreKeys picks a mapping based upon keyboard and country setting. I could modify the module to disable itself if it loads in an unsupported configuration. The reason I don’t didn’t this is because RISC OS does not broadcast notification of a change of keyboard/country so the front-end app may not know when there is a supported configuration.
Are you implying that write access is all or nothing? It can’t be partitioned into user-accessible directories?
Excuse me? Trying to support non-standard (as in “on the keyboard”) characters, and doing so in several country settings and different keyboards (with configration to allow more to be added easily) is being a Little Englander? |
Rick Murray (539) 13840 posts |
Unfortunately Stuart’s software is not the same thing, and http://cerilica.com/ appears to be a Japanese dating site!? [looks like, via archive.org, the keyboard was only available for a short time in 2001] Do you know where I could obtain a copy of the MMK driver for experimentation/testing? |
Tim Rowledge (1742) 170 posts |
T’is true. I know I am a bad person because of it. I plead youth and inexperience combined with long and faithful service. If I’m gradually getting to understand the problem, it seems like I need an extended/replaced keyboard driver that can deal with my extra needs as well as providing normal service for mundane software. I suspect that it would be easier to live with if a single kind of event were produced rather than some combination of normal-key + odd-stuff. Since it seems a bit unlikely that extend the key press event could work – older software wouldn’t know about up/down and so would presumably end up ggeettiinngg eevveerryy kkeeyy ttwwiiccee!! – another event would be required and so the poll masks would need changing etc. |
Rick Murray (539) 13840 posts |
https://www.riscosopen.org/viewer/view/castle/RiscOS/Sources/Programmer/KeyWatch/ ? |
Rick Murray (539) 13840 posts |
FWIW, copy of posting on csam: Hi, Wow. It’s been almost a year. Version 0.08 of MoreKeys is now available, from the usual place: http://www.heyrick.co.uk/software/morekeys/ Here’s what’s new since the last release:
The latter part also provides a framework for disabling MoreKeys while the Cerilica MMK driver is in use (apparently there is a clash), however because I do not have a copy of this driver module, I cannot detect when it is in use… can anybody help with this? Best wishes, Rick. As a special extra to ROOL readers – MoreKeys now supports a “colourful” mode that will be able to be switched on and off by a setup program (not yet available). If you want to see this in action, create the file “Choices:MoreKeys.settings” in !Zap or !StrongEd. Switch to byte mode (Ctrl-Shift-F2 in Zap) and enter the following (bytes shown in hex; you can’t do this in !Edit…): |
Ralph Barrett (1603) 154 posts |
Rick said > “As a special extra to ROOL readers – MoreKeys now supports a “colourful” mode that will be able to be switched on and off by a setup program (not yet available). If you want to see this in action, create the file “Choices:MoreKeys.settings” in !Zap or !StrongEd. Switch to byte mode (Ctrl-Shift-F2 in Zap) and enter the following (bytes shown in hex; you can’t do this in !Edit…): Never say “can’t”. In !Edit type “MKS1” then insert control characters ‘00_hex’ and ‘01_hex’ by using CTRL<0> and then CTRL<1>. Then use !ZAP in byte mode to double check that your data file is correct;-) Ralph |
nemo (145) 2546 posts |
Rick responded
You don’t mean ‘unable’. What you should have done is written a Key Handler.
That’s exactly what keyboard handlers already do. Mine for example used a new International service code to request accent mappings (and things like hard space) so that new country/alphabet providers (like my CeriAlpha module) could implement things like EBCDIC, and the keyboard still work correctly! Using such a system you can type
Or write a Key Handler.
Outside the desktop? (Rhetorical)
No Rick, you shouldn’t wilfully break things and then wait for people to complain. Preventing key transitions getting to the key handler is bad practice and should be avoided.
I did. It’s called a Key Handler. People get to choose which keyboard handler to use and then they use it. What no one wants is to find that their keyboard no longer functions correctly after they double-clicked some program that misguidedly loaded your module and broke the handler.
By NOT passing on every key transition you will break anything that requires that key transition.
No you can’t. There’s no way to identify key handers. Country, alphabet, keyboard, yes. But they aren’t the same thing as the keyboard handler.
No. Doing so in a way that only works with what you happen to have installed in Aldershot is the problem. You should have written a keyboard handler. |
nemo (145) 2546 posts |
Bother. I wrote a long reply to Tim explaining how DeepKeys could be extended to solve his problem… and then realised that no, I was right in the first place – it needs to be a bulk interface. First the explanation of the (I now realise, misguided) interface: Tim worried
As it happens, no. I should explain how DeepKeys works so you can see how it can help. DeepKeys sits on KeyV (listening for key transitions) and the various buffering vectors (used for getting things from and putting things in the keyboard buffer). It also has a Wimp Filter which is used to modify keypress events. DeepKeys maintains a map of eleven modifiers (including the Logo and Menu keys which can therefore be used as modifiers without additional application code) and buffers the current state of those modifiers with every keypress that enters the keyboard buffer. Then, when the Wimp removes a keypress from the buffer, DeepKeys puts the corresponding modifier state to one side. If the keypress is delivered as a Keypress Poll event, then DeepKeys’ filter appends the modifier state to the message. Thus the application gets the state of the modifier keys at the time the keypress was emitted by the keyboard handler (whatever that may be). As well as the modifiers, it also stores the key number of the key transition that caused the keypress to be buffered. So regardless of the fact that most keyboard handlers buffer the same code for Return, Enter, Ctrl-M and Ctrl-Shift-M, recipients of the Wimp’s KeyPress event can tell them apart unambiguously (and can even tell which Shift and Ctrl were used). Finally, DeepKeys is so called because it also expands the concept of a keypress to be a word rather than a byte. This means one can buffer keypress &12345, and it will be delivered to the Wimp application or caller of OS_ReadC intact. That was intended to support virtual keys such as a ‘scan’ button on a scanner, but hasn’t as far as I know been used yet. So that’s where we’ve been for over a decade. What I am proposing now is a small change. As DeepKeys sits on both KeyV and InsV, it can monitor what the keyboard handler does (without making any assumptions about the few the author may have come into contact with) and can therefore tell when a key transition (up or down) did not cause a keypress to be buffered. Such ‘invisible’ transitions can then be made visible by buffering a special code (say &12300). When DeepKey’s filter sees that being delivered to an application, it would transform the event into a new “key transition” event. So bufferable transitions get delivered by KeyPress event as they always did, other transitions get delivered by a new message. Existing applications don’t suddenly start receiving KeyPress events when you release the Shift key (for example), but apps that need to know… Oh. It was at this point I realised that proposal wouldn’t work. I had thought that delivering key transitions only to the application with the focus was a good thing. It’s not. The problem is that if there are keys held down when your application loses the focus, then it won’t get the corresponding key up transition messages and will continue to believe they are held down when it regains the focus. For example: F12. This is why key transitions can’t be a one-at-a-time interface but need to be a bulk interface. Really this needs to be a TaskModule-like service – apps register a pollword with this KeyState module and, whenever the state changes, it messages just those applications with a KeyStateChanged message. 256 key states is only 32 bytes, so it’s not a big message. This also saves the applications from having to maintain their own map (they just keep the last state they knew about). Add a SWI to read the current state and hey presto, job done. Yes the KeyStateChanged message could just be broadcast. That would make the module utterly trivial. (Having written a TaskModule clone I can say quite confidently that it’s quite a bit of work to get right). Thanks Tim, you’ve saved me some pointless hacking. |
nemo (145) 2546 posts |
Rick said
Your module needs to sit on InsV as well as KeyV (or EventV) – pass on the transition event then act on it on the way out again, but only if the key handler didn’t buffer anything. There is still a danger of a clash (eg your keypress may be a dead accent), but it’s an escapable one (the next keypress is unintended, but can be deleted). This is better than permanently disabling an unknown amount of keyboard handler functionality, I think. |
Rick Murray (539) 13840 posts |
I wrote a longer message earlier, but pressed Backspace instead of Delete by accident (they’re right beside each other on the netbook keyboard) and as a result the browser went back a hop and threw away my message. So I went out and did something else for a while…
Certainly, that is something to consider.
The only keys I claim are alphanumerics (etc) when Alt and Ctrl are held down. The actual key down/key up for Ctrl and Alt (and Shift) are recorded but are passed on, for what ought to be blatantly obvious reasons. Indeed, the key is swallowed primarily because dealing with it further up the chain is more complicated.
Don’t see why not. InstallKeyHandler has a call to return the address of the current keyboard handler. Said handler will be in a module, located at an address of which the returned keyboard handler will be a part of. Said module will have a name. If you were, say, to send me your MMK driver, I reckon I could tell it apart from others with this method. If the driver does not correctly identify itself, there will still be the possibility of a “signature”, something in the module that is unique to itself. From that, the identity of the keyboard handler can be derived. Or, more specifically, the identity of handlers where MoreKeys should error-and-exit.
Firstly, I live in France. Secondly, it was tested on a Beagle with both UK and French keyboards, plus another person did a key mapping for Germany so we can presume three European keyboard layouts and the respective driver(s) were involved. To date, and MoreKeys is a year old now, you are the second person that has reported a problem.1 Does the Cerilica MMK driver use Ctrl and Alt together for additional keypresses? Not Ctrl this or Alt that, but Ctrl and Alt. 1 It was reported that Ctrl-Alt-Tab is used by MoreDesk; so MoreKeys was modified to leave that alone. It has always left Fkeys alone as RISC OS itself uses Ctrl-Alt-Fx combinations for switching layout on the fly.
Er, no. Do you know what MoreKeys does ? It is a front-end UI thing (hence why it doesn’t work in the command line) that works in a manner similar to a long-press on the virtual keyboard of an Android device. If I am some day to write a MoreKeys2, it may be implemented as a Wimp pre-poll filter. The keyboard trapping is a means of getting the keypress from the low level to the UI without it being messed around with. To have the keyboard driver do this makes about as much sense as having the USB stack generate scroll events!
I am sorry it appears to clash with your keyboard driver. I would, if I had specifics, include code to detect your driver and leave it alone. Unfortunately the standard drivers are simpler, so MoreKeys offers a highly configurable way to provide the same sort of functionality as you are used to, albeit with a different approach, to those who are not able to enjoy all the extras that you take for granted. In this situation, with the generic RISC OS drivers, MoreKeys compliments the existing methods with something that it would be nice to have built in to RISC OS itself. Maybe some day, but for now… |
Chris Hall (132) 3554 posts |
Surely the use of characters other than the permitted ASCII A-Z a-z 0-9 and a few others like ‘!’ and ‘.’ in filenames is prohibited. If they can’t be typed in the command line or displayed by a ‘*CAT’ command then they are rather dangerous to use in filenames. |