modules/controls/src/main/java/com/sun/javafx/scene/control/inputmap/KeyBinding.java

Print this page
rev 9240 : 8076423: JEP 253: Prepare JavaFX UI Controls & CSS APIs for Modularization
   1 /*
   2  * Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package com.sun.javafx.scene.control.behavior;
  27 
  28 import com.sun.javafx.util.Utils;
  29 import static com.sun.javafx.scene.control.behavior.OptionalBoolean.ANY;
  30 import static com.sun.javafx.scene.control.behavior.OptionalBoolean.FALSE;
  31 import static com.sun.javafx.scene.control.behavior.OptionalBoolean.TRUE;
  32 import com.sun.javafx.tk.Toolkit;
  33 import javafx.event.EventType;
  34 import javafx.scene.control.Control;
  35 import javafx.scene.input.KeyCode;
  36 import javafx.scene.input.KeyEvent;
  37 




  38 /**
  39  * KeyBindings are used to describe which action should occur based on some
  40  * KeyEvent state and Control state. These bindings are used to populate the
  41  * keyBindings variable on BehaviorBase. The KeyBinding can be subclassed to
  42  * add additional matching criteria. A match in a subclass should always have
  43  * a specificity that is 1 greater than its superclass in the case of a match,
  44  * or 0 in the case where there is no match.
  45  *
  46  * Note that this API is, at present, quite odd in that you use a constructor
  47  * and then use shift(), ctrl(), alt(), or meta() separately. It gave me an
  48  * object-literal like approach but isn't ideal. We will want some builder
  49  * approach here (similar as in other places).


  50  */
  51 public class KeyBinding {
  52     private KeyCode code;
  53     private EventType<KeyEvent> eventType = KeyEvent.KEY_PRESSED;
  54     private String action;
  55     private OptionalBoolean shift = FALSE;
  56     private OptionalBoolean ctrl = FALSE;
  57     private OptionalBoolean alt = FALSE;
  58     private OptionalBoolean meta = FALSE;
  59 
  60     public KeyBinding(KeyCode code, String action) {
  61         this.code = code;
  62         this.action = action;
  63     }
  64 
  65     public KeyBinding(KeyCode code, EventType<KeyEvent> type, String action) {








  66         this.code = code;
  67         this.eventType = type;
  68         this.action = action;
  69     }
  70 
  71     public KeyBinding shift() {
  72         return shift(TRUE);
  73     }
  74 
  75     public KeyBinding shift(OptionalBoolean value) {
  76         shift = value;
  77         return this;
  78     }
  79 
  80     public KeyBinding ctrl() {
  81         return ctrl(TRUE);
  82     }
  83 
  84     public KeyBinding ctrl(OptionalBoolean value) {
  85         ctrl = value;
  86         return this;
  87     }
  88 
  89     public KeyBinding alt() {
  90         return alt(TRUE);
  91     }
  92 
  93     public KeyBinding alt(OptionalBoolean value) {
  94         alt = value;
  95         return this;
  96     }
  97     
  98     public KeyBinding meta() {
  99         return meta(TRUE);
 100     }
 101 
 102     public KeyBinding meta(OptionalBoolean value) {
 103         meta = value;
 104         return this;
 105     }
 106     
 107     public KeyBinding shortcut() {
 108         if (Toolkit.getToolkit().getClass().getName().endsWith("StubToolkit")) {
 109             // FIXME: We've hit the terrible StubToolkit (which only appears 
 110             // during testing). We will dumb down what we do here
 111             if (Utils.isMac()) {
 112                 return meta();
 113             } else {
 114                 return ctrl();
 115             }
 116         } else {
 117             switch (Toolkit.getToolkit().getPlatformShortcutKey()) {
 118                 case SHIFT:
 119                     return shift();
 120 
 121                 case CONTROL:
 122                     return ctrl();
 123 
 124                 case ALT:
 125                     return alt();
 126 
 127                 case META:
 128                     return meta();
 129 
 130                 default:
 131                     return this;
 132             }
 133         }
 134     }
 135 


 136     public final KeyCode getCode() { return code; }
 137     public final EventType<KeyEvent> getType() { return eventType; }
 138     public final String getAction() { return action; }
 139     public final OptionalBoolean getShift() { return shift; }
 140     public final OptionalBoolean getCtrl() { return ctrl; }
 141     public final OptionalBoolean getAlt() { return alt; }
 142     public final OptionalBoolean getMeta() { return meta; }
 143 
 144     public int getSpecificity(Control control, KeyEvent event) {
 145         int s = 0;
 146         if (code != null && code != event.getCode()) return 0; else s = 1;
 147         if (!shift.equals(event.isShiftDown())) return 0; else if (shift != ANY) s++;
 148         if (!ctrl.equals(event.isControlDown())) return 0; else if (ctrl != ANY) s++;
 149         if (!alt.equals(event.isAltDown())) return 0; else if (alt != ANY) s++;
 150         if (!meta.equals(event.isMetaDown())) return 0; else if (meta != ANY) s++;
 151         if (eventType != null && eventType != event.getEventType()) return 0; else s++;
 152         // We can now trivially accept it
 153         return s;
 154     }
 155 

 156     @Override public String toString() {
 157         return "KeyBinding [code=" + code + ", shift=" + shift +
 158                 ", ctrl=" + ctrl + ", alt=" + alt + 
 159                 ", meta=" + meta + ", type=" + eventType + 
 160                 ", action=" + action + "]";









































 161     }


 162 }
   1 /*
   2  * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 package com.sun.javafx.scene.control.inputmap;

  26 
  27 import com.sun.javafx.util.Utils;



  28 import com.sun.javafx.tk.Toolkit;
  29 import javafx.event.EventType;

  30 import javafx.scene.input.KeyCode;
  31 import javafx.scene.input.KeyEvent;
  32 
  33 import java.util.Objects;
  34 
  35 import static com.sun.javafx.scene.control.inputmap.KeyBinding.OptionalBoolean.*;
  36 
  37 /**
  38  * KeyBindings are used to describe which action should occur based on some
  39  * KeyEvent state and Control state. These bindings are used to populate the
  40  * keyBindings variable on BehaviorBase. The KeyBinding can be subclassed to
  41  * add additional matching criteria. A match in a subclass should always have
  42  * a specificity that is 1 greater than its superclass in the case of a match,
  43  * or 0 in the case where there is no match.
  44  *
  45  * Note that this API is, at present, quite odd in that you use a constructor
  46  * and then use shift(), ctrl(), alt(), or meta() separately. It gave me an
  47  * object-literal like approach but isn't ideal. We will want some builder
  48  * approach here (similar as in other places).
  49  *
  50  * @since 9
  51  */
  52 public class KeyBinding {
  53     private final KeyCode code;
  54     private final EventType<KeyEvent> eventType;

  55     private OptionalBoolean shift = FALSE;
  56     private OptionalBoolean ctrl = FALSE;
  57     private OptionalBoolean alt = FALSE;
  58     private OptionalBoolean meta = FALSE;
  59 
  60     public KeyBinding(KeyCode code) {
  61         this(code, null);

  62     }
  63 
  64     /**
  65      * Designed for 'catch-all' situations, e.g. all KeyTyped events.
  66      * @param type
  67      */
  68     public KeyBinding(EventType<KeyEvent> type) {
  69         this(null, type);
  70     }
  71 
  72     public KeyBinding(KeyCode code, EventType<KeyEvent> type) {
  73         this.code = code;
  74         this.eventType = type != null ? type : KeyEvent.KEY_PRESSED;

  75     }
  76 
  77     public final KeyBinding shift() {
  78         return shift(TRUE);
  79     }
  80 
  81     public final KeyBinding shift(OptionalBoolean value) {
  82         shift = value;
  83         return this;
  84     }
  85 
  86     public final KeyBinding ctrl() {
  87         return ctrl(TRUE);
  88     }
  89 
  90     public final KeyBinding ctrl(OptionalBoolean value) {
  91         ctrl = value;
  92         return this;
  93     }
  94 
  95     public final KeyBinding alt() {
  96         return alt(TRUE);
  97     }
  98 
  99     public final KeyBinding alt(OptionalBoolean value) {
 100         alt = value;
 101         return this;
 102     }
 103     
 104     public final KeyBinding meta() {
 105         return meta(TRUE);
 106     }
 107 
 108     public final KeyBinding meta(OptionalBoolean value) {
 109         meta = value;
 110         return this;
 111     }
 112     
 113     public final KeyBinding shortcut() {
 114         if (Toolkit.getToolkit().getClass().getName().endsWith("StubToolkit")) {
 115             // FIXME: We've hit the terrible StubToolkit (which only appears 
 116             // during testing). We will dumb down what we do here
 117             if (Utils.isMac()) {
 118                 return meta();
 119             } else {
 120                 return ctrl();
 121             }
 122         } else {
 123             switch (Toolkit.getToolkit().getPlatformShortcutKey()) {
 124                 case SHIFT:
 125                     return shift();
 126 
 127                 case CONTROL:
 128                     return ctrl();
 129 
 130                 case ALT:
 131                     return alt();
 132 
 133                 case META:
 134                     return meta();
 135 
 136                 default:
 137                     return this;
 138             }
 139         }
 140     }
 141 
 142 
 143 
 144     public final KeyCode getCode() { return code; }
 145     public final EventType<KeyEvent> getType() { return eventType; }

 146     public final OptionalBoolean getShift() { return shift; }
 147     public final OptionalBoolean getCtrl() { return ctrl; }
 148     public final OptionalBoolean getAlt() { return alt; }
 149     public final OptionalBoolean getMeta() { return meta; }
 150 
 151     public int getSpecificity(KeyEvent event) {
 152         int s = 0;
 153         if (code != null && code != event.getCode()) return 0; else s = 1;
 154         if (!shift.equals(event.isShiftDown())) return 0; else if (shift != ANY) s++;
 155         if (!ctrl.equals(event.isControlDown())) return 0; else if (ctrl != ANY) s++;
 156         if (!alt.equals(event.isAltDown())) return 0; else if (alt != ANY) s++;
 157         if (!meta.equals(event.isMetaDown())) return 0; else if (meta != ANY) s++;
 158         if (eventType != null && eventType != event.getEventType()) return 0; else s++;
 159         // We can now trivially accept it
 160         return s;
 161     }
 162 
 163     /** {@inheritDoc} */
 164     @Override public String toString() {
 165         return "KeyBinding [code=" + code + ", shift=" + shift +
 166                 ", ctrl=" + ctrl + ", alt=" + alt + 
 167                 ", meta=" + meta + ", type=" + eventType + "]";
 168     }
 169 
 170     /** {@inheritDoc} */
 171     @Override public boolean equals(Object o) {
 172         if (this == o) return true;
 173         if (!(o instanceof KeyBinding)) return false;
 174         KeyBinding that = (KeyBinding) o;
 175         return Objects.equals(getCode(), that.getCode()) &&
 176                 Objects.equals(eventType, that.eventType) &&
 177                 Objects.equals(getShift(), that.getShift()) &&
 178                 Objects.equals(getCtrl(), that.getCtrl()) &&
 179                 Objects.equals(getAlt(), that.getAlt()) &&
 180                 Objects.equals(getMeta(), that.getMeta());
 181     }
 182 
 183     /** {@inheritDoc} */
 184     @Override public int hashCode() {
 185         return Objects.hash(getCode(), eventType, getShift(), getCtrl(), getAlt(), getMeta());
 186     }
 187 
 188     public static KeyBinding toKeyBinding(KeyEvent keyEvent) {
 189         KeyBinding newKeyBinding = new KeyBinding(keyEvent.getCode(), keyEvent.getEventType());
 190         if (keyEvent.isShiftDown()) newKeyBinding.shift();
 191         if (keyEvent.isControlDown()) newKeyBinding.ctrl();
 192         if (keyEvent.isAltDown()) newKeyBinding.alt();
 193         if (keyEvent.isShortcutDown()) newKeyBinding.shortcut();
 194         return newKeyBinding;
 195     }
 196 
 197     /**
 198      * A tri-state boolean used with KeyBinding.
 199      */
 200     public enum OptionalBoolean {
 201         TRUE,
 202         FALSE,
 203         ANY;
 204 
 205         public boolean equals(boolean b) {
 206             if (this == ANY) return true;
 207             if (b && this == TRUE) return true;
 208             if (!b && this == FALSE) return true;
 209             return false;
 210         }
 211     }
 212 
 213 }