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 }
|