@DATABASE "Keyboard"
@AUTHOR   "Paul Manias"
@NODE     "Main" "Keyboard Object Documenation"

@{b}@{u}OBJECT DOCUMENTATION@{uu}@{ub}
Name:      @{"KEYBOARD" LINK "Description"}
Date:      February 1998
Author:    Paul Manias
Copyright: DreamWorld Productions, 1996-1998.  All rights reserved.

@{b}@{u}CHANGES VERSION 1.0@{uu}@{ub}
This document was completely revised.

@EndNode
---------------------------------------------------------------------------
@NODE "Description" "Object: Keyboard"

@{b}@{u}OBJECT@{uu}@{ub}
Name:    Keyboard
Version: 1
ID:      ID_KEYBOARD
Module:  Keyboard
Include: @{"input/keyboard.h" LINK "GMSDev:Includes/input/keyboard.h/Main"}
Type:    Simple

@{b}@{u}DESCRIPTION@{uu}@{ub}
The purpose of the Keyboard object is to provide a system interface between
applications and the computer keyboard.  Where possible keys can be read as
ASCII  values,  which makes character detection much easier.  There is full
support  for  detecting  held and released keys, key combinations, repeated
keys  and  so  on.   A special Auto-Shift feature also allows the system to
handle changing characters to their upper-case equivalents when a shift key
is held or the Caps-Lock key is on.

Currently  you  can get a user's key presses by calling the Query() action.
The  keyboard  object  will  soon  allow you to Write() codes to the system
buffer,  allowing  you  to  send codes to all other programs in the system.
Please  examine  all  fields  and  read  the  Query()  action to get a full
overview of the Keyboard object.

@{b}@{u}ACTIONS@{uu}@{ub}
The Keyboard object supports the following actions:

     @{"Free()" LINK "GMSDev:AutoDocs/Kernel.guide/Free()"}  - Free the object.
     @{"Get()" LINK "GMSDev:AutoDocs/Kernel.guide/Get()"}   - Get a new keyboard structure.
     @{"Init()" LINK "GMSDev:AutoDocs/Kernel.guide/Init()"}  - Initialise a keyboard object.
   * @{"Query()" LINK "KEY_Query()"} - Read all keys since the last Query().

@{b}@{u}STRUCTURE@{uu}@{ub}
The Keyboard object consists of the following public fields:

     @{"AmtRead" LINK "KEY_AmtRead"} - Amount of keys read since last Query().
     @{"Buffer" LINK "KEY_Buffer"}  - Points to your personal keyboard buffer.
     @{"Flags" LINK "KEY_Flags"}   - Special behaviour flags.
     @{"Size" LINK "KEY_Size"}    - The maximum amount of elements that your Buffer can hold.

The Buffer is a child array, whose size is determined by the value given in
the  Key->Size  field  upon  initialisation.   The  array  structure looks
like this:

  struct KeyEntry {
    WORD @{"Qualifier" LINK "KE_Qualifier"};
    BYTE @{"Value"     LINK "KE_Value"};
    BYTE Reserved;
  };

@EndNode
---------------------------------------------------------------------------
@NODE "KEY_AmtRead" "Object: Keyboard"

@{b}@{u}FIELD@{uu}@{ub}
Name:   AmtRead
Type:   WORD
Status: Read Only.

@{b}@{u}DESCRIPTION@{uu}@{ub}
Whenever  you  Query() the keyboard, this field will be updated to tell you
the  amount  of keystrokes that were read into the Buffer.  If no keys were
pressed since the last time you called Query(), AmtRead will read as NULL.

@{b}@{u}NOTE@{uu}@{ub}
The  amount of keys read will never exceed the number specified in the Size
field.

@{b}@{u}SEE ALSO@{uu}@{ub}
Field: @{"Buffer" LINK "KEY_Buffer"}

@EndNode
---------------------------------------------------------------------------
@NODE "KEY_Buffer" "Object: Keyboard"

@{b}@{u}FIELDS@{uu}@{ub}
Names:  Buffer
Type:   struct KeyEntry *
Status: Read Only.

@{b}@{u}DESCRIPTION@{uu}@{ub}
This  field  points  to a KeyEntry array, which contains the keystrokes for
your  Keyboard  object.   The  amount  of  keys  that the array can hold is
dependent  on the Size field.  For information on how to read keys from the
Buffer, see the KeyEntry fields.

You  can  directly  write  to the array elements if you wish, this will not
affect the object.

@{b}@{u}SEE ALSO@{uu}@{ub}
Field:    @{"Size" LINK "KEY_Size"}
KeyEntry: @{"Qualifier" LINK "KE_Qualifier"}
          @{"Value" LINK "KE_Value"}

@EndNode
---------------------------------------------------------------------------
@NODE "KEY_Flags" "Object: Keyboard"

@{b}@{u}FIELD@{uu}@{ub}
Name:   Flags
Type:   WORD
Status: Read/Write

@{b}@{u}DESCRIPTION@{uu}@{ub}
This field contains special flags that affect the behaviour of the Keyboard
object.   Some  flags  are dynamic (you can switch them on/off whenever you
want), while others may be static (can only be set on initialisation).

  @{b}KF_AUTOSHIFT (Dynamic)@{ub}
  If you set this flag then all characters of the alphabet will
  be taken to upper-case if CAPS-LOCK is on.  If a SHIFT key is being held,
  then non-alphabetic characters will also be affected (e.g. 1 -> !).

  @{b}KF_GLOBAL (Dynamic)@{ub}
  Setting this flag causes your Task to receive every single keyboard
  event, wether or not they are directed at your Task.  Use of this flag
  can be necessary for 'hidden' applications that use special hot-keys
  for user input.

@EndNode
---------------------------------------------------------------------------
@NODE "KEY_Size" "Object: Keyboard"

@{b}@{u}FIELD@{uu}@{ub}
Name:      Size
Type:      LONG
Default:   50
Range:     1 - 200
On Change: Cannot change after initialisation.
Status:    Read/Init

@{b}@{u}DESCRIPTION@{uu}@{ub}
This  field  defines  the  size of your keyboard Buffer.  If you accept the
default  of  50,  that  means you will be able to read up to 50 key presses
every  time  you  call  Query().   This  is more than enough for 99% of all
programs.

Note  that  this field specifies the array size, not the byte size.  If you
want  to  know  what  the byte size is of the Buffer, it is calculated with
this formula:

   ByteSize = Key->Size * sizeof(struct KeyBuffer);

Note  that  if  you  attempt  to  specify  a Size greater than 200, it will
automatically be brought back to the maximum of 200 on initialisation.

@{b}@{u}SEE ALSO@{uu}@{ub}
Field: @{"Buffer" LINK "KEY_Buffer"}

@EndNode
--------------------------------------------------------------------------
@NODE "KE_Qualifier" "Structure: KeyEntry"

@{b}@{u}FIELD@{uu}@{ub}
Name: Qualifier
Type: WORD

@{b}@{u}DESCRIPTION@{uu}@{ub}
The  Qualifier  field  contains  any extra key combinations and information
that is relevant to the Value field.  Probably the most important flags are
KQ_HELD and KQ_RELEASED, as they tell you the status of the key.

   @{b}KQ_CAPSLOCK@{ub}
   Set if Caps-Lock is active for this key.

   @{b}KQ_CONTROL@{ub}
   This key is being held in combination with the Ctrl key.

   @{b}KQ_HELD@{ub}
   This key is being pressed.

   @{b}KQ_KEYPAD@{ub}
   This key was pressed from the numeric keypad.

   @{b}KQ_LALT@{ub}
   This key is being held in combination with the Left-Alt key.

   @{b}KQ_LCOMMAND@{ub}
   This key is being held in combination with the Left-Command (Amiga) key.

   @{b}KQ_LSHIFT@{ub}
   This key is being held in combination with Left-Shift.

   @{b}KQ_RALT@{ub}
   This key is being held in combination with the Right-Alt key.

   @{b}KQ_RCOMMAND@{ub}
   This key is being held in combination with the Right-Command (Amiga)
   key.

   @{b}KQ_RSHIFT@{ub}
   This key is being held in combination with Right-Shift.

   @{b}KQ_RELEASED@{ub}
   The key has been released by the user.

   @{b}KQ_REPEAT@{ub}
   This flag is used when the user has pressed a key and holds it down.

   @{b}KQ_SHIFT@{ub}
   This is a special flag combination (KQ_LSHIFT | KQ_RSHIFT) for those
   of you that don't care about the difference between left and right
   shift keys.

@{b}@{u}SEE ALSO@{uu}@{ub}
KeyEntry: @{"Value" LINK "KE_Value"}

@EndNode
--------------------------------------------------------------------------
@NODE "KE_Value" "Structure: KeyEntry"

@{b}@{u}FIELD@{uu}@{ub}
Name: Value
Type: UBYTE

@{b}@{u}DESCRIPTION@{uu}@{ub}
The   Value  field  contains  the  code  for  the  keystroke.   Values  are
represented in ASCII format where possible, which has a range of 00 - 0x7F.
This  allows  you  to  easily  pick up values like 'a', 'f', '~', <Return>,
<Tab>  and  so  on.   If  you are using the KF_AUTOSHIFT flag, you can also
receive upper-case characters like 'A', '!', '}', etc.

If  you  want to detect key combinations such as CTRL+M, LCOMMAND+LSHIFT+S,
then you need to read the Qualifier field which is paired with the Value.

@{b}@{u}Special Keys@{uu}@{ub}
A  special  set of key values is available for detecting keys such as Help,
Shift,  F1  -  F20, Cursor Keys, and so on.  These values start just out of
the  ASCII range, 0x80 - 0xFE.  Currently available special keys are:

  K_SLEFT     - "Special" key on left
  K_HELP      - Help
  K_LSHIFT    - Left Shift
  K_RSHIFT    - Right Shift
  K_CAPS      - Caps Lock
  K_CTRL      - Control
  K_LALT      - Left Alt
  K_RALT      - Right Alt
  K_LAMIGA    - Left Amiga
  K_RAMIGA    - Right Amiga
  K_F1..K_F20 - Function Keys 1 - 20
  K_UP        - Cursor Up
  K_DOWN      - Cursor Down
  K_RIGHT     - Cursor Right
  K_LEFT      - Cursor Left
  K_SRIGHT    - "Special" key on right

To  assist  you in your programming, some ASCII constants are also provided
for the more tricky characters:

  K_BAKSPC    - Backspace
  K_TAB       - Tab
  K_RETURN    - Return
  K_ESC       - Escape
  K_DEL       - Delete

@{b}@{u}SEE ALSO@{uu}@{ub}
KeyEntry: @{"Qualifier" LINK "KE_Qualifier"}

@EndNode
--------------------------------------------------------------------------
@NODE "KEY_Query()" "Object: Keyboard"

@{b}@{u}ACTION@{uu}@{ub}
Name:  Query(Keyboard)
Short: Get the latest key-presses since your last Query().

@{b}@{u}DESCRIPTION@{uu}@{ub}
You need to use the Query() action when you want to get all the key-presses
since your last Query().  The internal procedure is as follows:

  1. Look at the global keyboard buffer.
  2. Find all waiting inputs for this task and store them in the Keyboard
     object that has been passed to Query().
  3. Store the amount of inputs in the AmtRead field.
  4. Finished.

Note  that  key-presses  are written starting with the oldest key first and
the  newest  key  last.   This ensures that if I type in 'Paul' that is the
order in which you read it, rather than 'luaP'.

If  there  is  a lot of input and your key buffer is not big enough to hold
all  the  waiting  key presses, you will get a full buffer that starts with
the oldest key.  You will not be able to get the latest key until your next
Query().  It is recommended that you Query() the keyboard at least every 50
micro-seconds if you want to receive all inputs quickly and accurately.

@{b}@{u}EXAMPLE@{uu}@{ub}
In  this  example the user holds the LEFT-SHIFT key, presses '1, 2, 3', and
then  lets  go of the shift key.  The table shows what the Keyboard->Buffer
will receive on Query(), in sequence:

  Qualifier              | Value
  -----------------------+-------------
  KQ_HELD, KQ_LSHIFT     | K_LSHIFT
  KQ_HELD, KQ_LSHIFT     | '1'
  KQ_RELEASED, KQ_LSHIFT | '1'
  KQ_HELD, KQ_LSHIFT     | '2'
  KQ_RELEASED, KQ_LSHIFT | '2'
  KQ_HELD, KQ_LSHIFT     | '3'
  KQ_RELEASED, KQ_LSHIFT | '3'
  KQ_RELEASED            | K_LSHIFT

If  the  user was to perform the above but hold the '1' key and then let go
of that and the shift key:

  Qualifier                         | Value
  ----------------------------------+-------------
  KQ_HELD, KQ_LSHIFT                | K_LSHIFT
  KQ_HELD, KQ_LSHIFT                | '1'
  KQ_HELD, KQ_LSHIFT, KQ_REPEAT     | '1'
  KQ_HELD, KQ_LSHIFT, KQ_REPEAT     | '1'
  KQ_HELD, KQ_LSHIFT, KQ_REPEAT     | '1'
  KQ_HELD, KQ_LSHIFT, KQ_REPEAT     | '1'
  KQ_HELD, KQ_LSHIFT, KQ_REPEAT     | '1'
  KQ_HELD, KQ_LSHIFT, KQ_REPEAT     | '1'
  KQ_HELD, KQ_LSHIFT, KQ_REPEAT     | '1'
  KQ_HELD, KQ_LSHIFT, KQ_REPEAT     | '1'
  KQ_HELD, KQ_LSHIFT, KQ_REPEAT     | '1'
  KQ_HELD, KQ_LSHIFT, KQ_REPEAT     | '1'
  KQ_HELD, KQ_LSHIFT, KQ_REPEAT     | '1'
  KQ_HELD, KQ_LSHIFT, KQ_REPEAT     | '1'
  KQ_HELD, KQ_LSHIFT, KQ_REPEAT     | '1'
  KQ_RELEASED, KQ_LSHIFT            | '1'
  KQ_RELEASED                       | K_LSHIFT

If  you  want to analyse keyboard output some more, load IceBreaker and run
the demo in:

  GMSDev:Source/C/Keyboard/Keyboard

@{b}@{u}SEE ALSO@{uu}@{ub}
Kernel:   @{"Query()" LINK "GMSDev:AutoDocs/Kernel.guide/Query()"}
KeyEntry: @{"Qualifier" LINK "KE_Qualifier"}
          @{"Value" LINK "KE_Value"}

@EndNode
--------------------------------------------------------------------------
