KeyboardMap.st
author Jan Vrany <jan.vrany@fit.cvut.cz>
Wed, 08 Feb 2017 23:58:18 +0000
branchjv
changeset 7969 2bac4f32553f
parent 7856 7c52e7a9a087
child 8035 8bbd397fe321
permissions -rw-r--r--
Allow individual applications to define their own shortcut mapping When a system wants to translate a shortcut into a logical action key, it asks a view to it's keyboard map which porivdes such translations. Histrically, there was only one such map kept in window device. To allow per-application customization, each view by default returns its parent's view map. The top level window then asks its underlaying application model for a map. This way, each application may provide its own shortcut mappings or override / inhibit global ones. Keyboard mappings may be chained to from a hiearchy: if a mapping is not found in given keyboard map, it's parent map (if any) is asked for the mapping. Usually a device's keyboard map is at the top of the hiearchy (but not necessarily)

"
 COPYRIGHT (c) 1993 by Claus Gittinger
	      All Rights Reserved

 This software is furnished under a license and may be used
 only in accordance with the terms of that license and with the
 inclusion of the above copyright notice.   This software may not
 be provided or otherwise made available to, or used by, any
 other person.  No title to or ownership of the software is
 hereby transferred.
"
"{ Package: 'stx:libview' }"

"{ NameSpace: Smalltalk }"

IdentityDictionary subclass:#KeyboardMap
	instanceVariableNames:'parent current'
	classVariableNames:''
	poolDictionaries:''
	category:'Interface-Support-UI'
!

!KeyboardMap class methodsFor:'documentation'!

copyright
"
 COPYRIGHT (c) 1993 by Claus Gittinger
	      All Rights Reserved

 This software is furnished under a license and may be used
 only in accordance with the terms of that license and with the
 inclusion of the above copyright notice.   This software may not
 be provided or otherwise made available to, or used by, any
 other person.  No title to or ownership of the software is
 hereby transferred.
"
!

documentation
"
    Instances of KeyboardMap are used for mapping keystrokes AND sequences
    of keystrokes to a logical function which is used by UI code. For
    example, it maps #Ctrls to #Accept logical function which is then
    used menu items and so on.

    This allows for changing a shortcut without changing the code.

    Keyboard maps may chained together, if a mapping is not found in
    a particular key map, lookup continues in its parent map (if any).
    Usually the grand-parent is device's standard map, see
    DeviceWorkstation >> keyboardMap (but not necessarily!!)

    The setup of device's map is done in the 'smalltalk.rc' or one of the
    'keyboard.rc' files during startup.

    To add a mapping (for example, to attach the logical function 'DoIt' to
    the key-combination Cmd-'d'):

        |m|

        m := Display keyboardMap.
        m bindValue:#DoIt to:#Cmdd.

    Key sequences can also be defined (hey emacs fans ;-) as in:

        |m|

        m := Display keyboardMap.
        m bindValue:#DoIt to:#Ctrlx followedBy:#Ctrld

    Key prefixes are defined in the DeviceWorkstation>>translateKey: method.
    Typical prefixes are Cmd (for Alt or Meta), Ctrl etc.
    Some keyboards offer both Alt and Meta keys - on those, the first has a
    prefix of Alt, the second has Cmd as prefix. Keyboards with only an Alt
    key will will create prefix codes of Cmd for that.

    To remove a mapping, use the same value for both logical and physical key,
    as in:

        |m|

        m := Display keyboardMap.
        m bindValue:#Cmdd to:#Cmdd.

    [see also:]
        WindowEvent WindowSensor WindowGroup
        View DeviceWorkstation

    [author:]
        Claus Gittinger
"
! !

!KeyboardMap methodsFor:'accessing'!

bindValue:logicalKey to:aKey
    "bind aLogicalKey to a rawKey.
     The event mechanism uses this to pass logical keyboard events
     to the application (such as #Copy, #Cut etc.) 
     instead of physical ones (such as #AltC, #AltX)"

    aKey == logicalKey ifTrue:[
        self removeKey:aKey ifAbsent:nil
    ] ifFalse:[
        self at:aKey put:logicalKey
    ]

    "Modified: 12.11.1996 / 10:30:56 / cg"
!

bindValue:logicalKey to:key1 followedBy:key2
    "bind aLogicalKey to a sequence of two rawKeys.
     The event mechanism uses this to pass logical keyboard events
     to the application (such as #Copy, #Cut etc.) 
     instead of physical ones (such as #AltC, #AltX)"

    |submap|

    submap := self at:key1 ifAbsent:[].
    submap isNil ifTrue:[
        submap := KeyboardMap new.
        self at:key1 put:submap.
    ].
    submap at:key2 put:logicalKey

    "Modified: 23.4.1996 / 21:55:04 / cg"
!

hasBindingFor:aKey
    "retrieve a logical key"

    current notNil ifTrue:[
        ^ current includesKey:aKey
    ].
    (self includesKey:aKey) ifTrue:[ ^ true ].
    parent notNil ifTrue:[ 
        parent hasBindingFor:aKey
    ].
    ^ false

    "Modified: / 02-02-2017 / 00:13:32 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

parent
    ^ parent
!

parent:aKeyboardMap
    parent := aKeyboardMap.
!

rawKeysForLogical: logicalKey
    "Return all raw keys for given )possibly) logical key.
     Example:
       #Copy -> #(Ctrlc) - depending on mappings
    "
    | map rawKeys |

    map := self.
    rawKeys := #().
    [ rawKeys isEmpty and:[ map notNil ] ] whileTrue:[
        map keysAndValuesDo:[ :raw :logical | logical == logicalKey ifTrue:[ rawKeys := rawKeys copyWith: raw ] ].
        map := map parent.
    ].
    ^ rawKeys

    "
    Screen current keyboardMap rawKeysForLogical: #Copy
    "

    "Created: / 08-02-2017 / 23:43:26 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

valueFor:aKey
    "retrieve a logical key"

    |whichMap value|

    whichMap := (current notNil ifTrue:[current] ifFalse:[self]).

    value := whichMap at:aKey ifAbsent:[ nil ].
    (value isMemberOf:KeyboardMap) ifTrue:[
        current := value.
        ^ nil.
    ].
    current := nil.
    value isNil ifTrue:[ 
        parent notNil ifTrue:[
            ^ parent valueFor: aKey
        ].
        "/ No mapping for given key, return it unmapped
        ^ aKey
    ].
    ^ value

    "Modified: / 23-04-1996 / 21:55:22 / cg"
    "Modified: / 04-02-2017 / 22:24:45 / Jan Vrany <jan.vrany@fit.cvut.cz>"
! !

!KeyboardMap class methodsFor:'documentation'!

version
    ^ '$Header: /cvs/stx/stx/libview/KeyboardMap.st,v 1.15 2014-12-18 16:13:06 cg Exp $'
! !