
 DeepKeys 2.10 (11 Feb 2020)  Cerilica 1999-2020
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

 NEW FOR 2.09: Now with ReadC functionality and improved Wimp message.

 DeepKeys has two functions, it extends the Wimp KeyPress message with
 modifiers and physical key number, and it implements a word-deep rather than
 byte-deep keyboard buffer (of limited use after RISC OS 3, see later).

 DeepKeys can be distributed with any program, PD or commercial, providing that
 this documentation is included intact, and that the following credit is
 reproduced in any other documentation, manuals and/or help files:

    DeepKeys  Cerilica 1999-2020  Contact: <deepkeys@cerilica.co.uk>


 KeyPress Wimp Poll Event
 ~~~~~~~~~~~~~~~~~~~~~~~~
 DeepKeys installs a wimp filter which extends the normal keypress event. Poll
 reason 8 returns a word-sized keypress code at block+24 as normal, but this is
 followed by a new information word at block+28 containing the state of the
 modifier keys at the time the keypress was detected, plus the physical key
 number of the non-modifier key generating the keypress:

  +0  Length - as of 2.09 this is now 32 to indicate the presence of modifiers
  +24 KeyPress code (word)
  +28 DeepKeys modifier state:
      b0 Left Shift    b1 Right Shift
      b2 Left Ctrl     b3 Right Ctrl
      b4 Left Alt      b5 Right Alt
      b6 Left Logo     b7 Right Logo
      b8 Menu key
      b9-14 reserved (0)
      b15 Always 0
      b16-31 Physical key number (16 bit for future expansion)

 Although the message length includes the modifier state as of 2.09, this is
 not the recommended way to detect its presence as it will fail to notice
 earlier versions of DeepKeys. It is better to set wimp block +28 to 1<<15
 before calling Wimp_Poll[Idle], as b15 of the modifiers is guaranteed to be
 clear. If that bit is set in a KeyPress event message, DeepKeys is absent.


 Keyboard Buffer
 ~~~~~~~~~~~~~~~
 DeepKeys implements a word-sized keyboard buffer. Consequently, all system
 calls that deal with the keyboard buffer now input and output word-sized
 values.

 Unfortunately a change in RO4's WindowManager makes this less useful than it
 was for RO2 and RO3. Whereas the Wimp used to be agnostic about the range of
 keypress codes, RO4's Wimp truncates keypress codes to a byte. This can also
 be seen in the changed behaviour of Wimp_ProcessKey, which used to take any
 value, but as of RO4 can only take values 0-&1FF.

 RO5 confuses the issue further by conflating keypress codes with Unicodes
 when operating in the UTF-8 Alphabet. Although it receives keypresses in UTF-8
 encoding and writes UTF-8 encoding to writeable icons, it buffers keypresses
 in UTF-32 form and so would confuse 'deep' keypresses even if it didn't
 truncate them.

 The intention was that 'deep' key ranges could be allocated to developers to
 represent additional non-keyboard buttons, such as the scan button on a
 scanner or meta functions such as "open browser", "start calculator" etc.
 This will not be possible without a change to the Wimp to revert to RO3
 behaviour.

 InsV, RemV and CnpV handle word-sized keypress codes. OS_Byte 138,0,<code>
 can take 'deep' key codes, and OS_ReadC returns word-sized values.

 As of 2.06, InsV and RemV can additionally insert, remove or inspect the
 modifier state in R3, in the format below, by setting R1b30 on entry. In
 block mode the buffer contains code/modifier word pairs). This bit is CLEAR
 on exit if DeepKeys 2.06+ is present (if set on exit, the module is not
 present and the call has failed due to the buffer number being out of range).
 If a keypress is removed by the normal RemV call, the associated modifers will
 be returned by the wimp filter, as below. Please note that this does not
 extend to OS_Byte,138, as register R3 might have been corrupted by ByteV
 claimants.

 As of 2.09, ReadC/RdchV can optionally return the modifier state at the same
 time as the keypress code, by setting R0 to a magic value and R1 to 1<<15.
 This is backwards compatible - if DeepKeys is not present, R1b15 will be set
 on exit. If DeepKeys 2.09+ is present, R1 contains the modifier state which
 is guaranteed to have b15 clear.


 Wimp Programming
 ~~~~~~~~~~~~~~~~
 If an application requires DeepKeys, it should RMEnsure it. DeepKeys has been
 allocated the common installation point of "<Boot$ToBeLoaded>.!!DeepKeys"
 (note double pling). Because DeepKeys replaces the keyboard buffering it can
 not be loaded on demand (unless VectorExtend is present) as it may disable
 other keyboard modules, so it is loaded as early as possible.

 If your application requires a particular version of DeepKeys and you find the
 installed version is too old, you should update the installation in your !Run
 file (this uses an alias only to limit line length for clarity):
 
   Unset X$Error
   Set Alias$1 Copy <Obey$Dir>.!!DeepKeys <Boot$ToBeLoaded>.* A~C~DFLN~PQ~S~T~V
   RMEnsure DeepKeys 2.10 X 1
   Unset Alias$1
   If LEN"<X$Error>" Then Error Unable to install DeepKeys: <X$Error>
   RMEnsure DeepKeys 2.10 Error Reboot to complete DeepKeys installation

 If an application wants to make use of DeepKeys if available, but does not
 require it, DeepKey's presence can be detected by setting bit 15 of block+28
 before calling Wimp_Poll or Wimp_PollIdle - this bit is guaranteed to be clear
 in a Key Pressed Event if the DeepKeys information word is present. As of 2.09
 the message length of 32 also indicates the presence of the modifier state.

   block%!28 = 1<<15
   SYS"Wimp_Poll",pollmask%,block% TO reason%
   CASE reason% OF
     WHEN 8: REM KeyPress
       IF block%!28 AND 1<<15 THEN
         REM No DeepKeys, sadly

 Most keyboards generate key codes for the Logo and Menu keys (Cerilica's MMK
 certainly does), but DeepKeys also treats them as modifiers, so an individual
 application can use combinations such as Logo-A just as if it were Ctrl-A.
 When operating like this, the code generated by the initial Logo or Menu
 keypress must be ignored (but not passed on). The key code returned will be of
 the unmodified keypress, but the Logo or Menu modifier will be flagged in the
 modifier state.

 The physical key number can be used to assign different actions to sets of
 keys that generate the same keypress code - Return and Enter for example.
 When implementing such a scheme, make sure that the DEFAULT action is that
 assigned to the most-common keypress, eg:

   REM Disambiguate keypress code by internal key number
   CASE block!24 OF
     WHEN 13:REM Return, Enter, Ctrl-M or Alt-kp1-kp3
       CASE (block!28)>>>16 OF
         WHEN &67: PROCkeypress_ENTER
         WHEN &54: PROCkeypress_CTRL_M
         WHEN &5C: PROCkeypress_ALT_1_3
         OTHERWISE:PROCkeypress_RETURN
       ENCASE

 This ensures sensible operation with future keyboards, and with keypresses
 not generated by the keyboard - see following section. (Note that prior to
 version 2.08, the Logo and Menu keys did not return a valid physical key
 number when pressed in isolation - they now do).


 Outside the desktop
 ~~~~~~~~~~~~~~~~~~~
 As of 2.09, DeepKeys can now deliver modifier state along with keypress codes
 from OS_ReadC, which is very convenient. This is done with a pair of magic
 values which ensures backwards compatibility:
 
   REM Disambiguate keypress code by internal key number
   SYS"OS_ReadC",&794B7044,1<<30 TO K%,M%
   CASE K% OF
     WHEN 13:REM Return, Enter, Ctrl-M or Alt-kp1-kp3
       CASE M%>>>16 OF
         WHEN &67: PROCkeypress_ENTER
         WHEN &54: PROCkeypress_CTRL_M
         WHEN &5C: PROCkeypress_ALT_1_3
         OTHERWISE:PROCkeypress_RETURN
       ENDCASE

 Much like the Wimp keypress message, DeepKey's absence can be detected if
 necessary:

   REM Detect DeepKeys' regretable absence, and build a poor substitute
   SYS"OS_ReadC",&794B7044,1<<30 TO K%,M%
   IF M%AND(1<<15) THEN M%=(INKEY(-1)AND3)OR(INKEY(-2)AND12)OR(INKEY(-3)AND48)


 InsV
 ~~~~
 Unlike the Kernel, DeepKeys does implement block mode for the keyboard buffer
 (bugfixed in 2.10).

 => r0  value (if r1b31 clear)
    r1  b0-29=0 (keyboard buffer), b31=block mode, b30=modifiers in R3/block
    r2  data block if r1b31 (bytes if b30 clear, else key,modifier word pairs)
    r3  length in bytes if r1b31, else modifiers if r1b30

 <= R1  b30 clear
    R2  corrupted if r1b31 clear, else ptr to first value NOT inserted
    R3  preserved if r1b31 clear, else number of bytes NOT inserted
     C  insertion failed

 InsV should be called with interrupts off. An event is issued if the buffer
 becomes full.

 RemV
 ~~~~
 Unlike the Kernel, DeepKeys does implement block mode for the keyboard buffer.

 => r1  =0 (buffer number), b31=block mode, b30=modifiers returned in R3/block
    r2  block to fill if r1b31 (key/modifier word pairs if r1b30)
    r3  block length in bytes if r1b31
     V  examine only

  single mode (r1b31=0)
 <= R0  corrupted, or next value for examine
    R1  b30 clear (to detect DeepKeys)
    R2  value removed, or corrupted for examine
     C  buffer empty

  block mode (r1b31=1, b30=0) THIS IS NOT COMPATIBLE WITH WORD-SIZED VALUES
 <= R2  pointer past buffer (containing truncated bytes)
    R3  bytes left in buffer
     C  buffer empty

  new block mode (r1b31=1, b30=1) THIS RETURNS WORD-SIZED VALUES AND MODIFIERS
 <= R2  pointer past buffer (containing value/modifier word-pairs)
    R3  bytes left in buffer
     C  buffer empty

 RemV should be called with interrupts off.

 CnpV
 ~~~~
 CnpV does not have a block mode, and is unchanged by DeepKeys.

 => r1  =0 (buffer number), no additional flags
     V  Flush, else
     C  free space, else entries (and NOT the number of bytes)

 <= R0  corrupted
    R1  b0-7 of count, or preserved for flush
    R2  b0-23=b8-31 of count, or preserved for flush
        i.e. for count, ORR R1,R1,R2,LSL#8

 CnpV should be called with interrupts off.

 ReadC/RdchV
 ~~~~~~~~~~~
 => r0  ="DpKy" (&794B7044)
    r1  =1<<15

 <= R0  keypress code as usual
    R1  modifier state (b15 clear) or 1<<15 if DeepKeys 2.09+ not present
    C   set if escape pressed

 If r0 or r1 are not set to these magic values, ReadC/RdchV operate as they
 always have. If DeepKeys 2.09+ is not present then R1 will be unchanged.


 Problems
 ~~~~~~~~
 Key codes inserted into the buffer by software, rather than by the keyboard,
 do not normally have modifier or physical keys associated with them (unless
 the new InsV call is used). When delivered to a Wimp program it will report
 the state of the keyboard modifiers at the time of the simulated keypress, and
 the physical key number of the last REAL keypress. This physical key number
 will NOT match the key code inserted. This is why Wimp applications must be
 careful about interpreting the physical key number, as described above.

 The DeepKeys module does not pass keyboard buffer events on to existing
 claimants of the InsV, RemV and CnpV vectors, and so must be loaded first to
 avoid disabling some utilities - hence the allocated install position
 "<Boot$ToBeLoaded>.!!DeepKeys". This is a consequence of the way these vectors
 are used, and cannot be avoided without vector claimant prioritisation, as
 performed by the VectorExtend module.

 A note of advice to authors of vector claimants: Don't assume that the API
 you know about is all the API there will ever be. If FooV takes R0-R3, that
 does not mean you can destroy the caller's R4 during a tail-call, intending
 to restore it on the way back out  lower priority claimants further down
 the chain may need that parameter. Be as transparent as possible on vectors.

 Release history
 ~~~~~~~~~~~~~~~
 2.10 (11 Feb 2020) Bugfix for InsV block insert with empty keyboard buffer
 2.09 (15 Mar 2019) RdchV/ReadC hook
 2.08 (14 Feb 2004) RemV block mode
 2.06 (23 Jul 2003) InsV block mode
 2.05 (07 Jul 2003) Strict flag compliance
 2.04 (26 Mar 2001) Refactored
 2.03 (11 Mar 2001) 32bit
 2.02 (23 Sep 2000) EventV/FilterManager mitigation for Darren Salt
 2.00 (05 Sep 2000) Wimp integration

 DeepKeys 2.10 is copyright  Cerilica 1999-2020
