2 * This file is part of lanterna (http://code.google.com/p/lanterna/).
4 * lanterna is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU Lesser General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 * Copyright (C) 2010-2015 Martin
19 package com
.googlecode
.lanterna
.input
;
21 import java
.util
.ArrayList
;
22 import java
.util
.Arrays
;
25 * Represents the user pressing a key on the keyboard. If the user held down ctrl and/or alt before pressing the key,
26 * this may be recorded in this class, depending on the terminal implementation and if such information in available.
27 * KeyStroke objects are normally constructed by a KeyDecodingProfile, which works off a character stream that likely
28 * coming from the system's standard input. Because of this, the class can only represent what can be read and
29 * interpreted from the input stream; for example, certain key-combinations like ctrl+i is indistinguishable from a tab
32 * Use the <tt>keyType</tt> field to determine what kind of key was pressed. For ordinary letters, numbers and symbols, the
33 * <tt>keyType</tt> will be <tt>KeyType.Character</tt> and the actual character value of the key is in the
34 * <tt>character</tt> field. Please note that return (\n) and tab (\t) are not sorted under type <tt>KeyType.Character</tt>
35 * but <tt>KeyType.Enter</tt> and <tt>KeyType.Tab</tt> instead.
38 public class KeyStroke
{
39 private final KeyType keyType
;
40 private final Character character
;
41 private final boolean ctrlDown
;
42 private final boolean altDown
;
43 private final boolean shiftDown
;
44 private final long eventTime
;
47 * Constructs a KeyStroke based on a supplied keyType; character will be null and both ctrl and alt will be
48 * considered not pressed. If you try to construct a KeyStroke with type KeyType.Character with this constructor, it
49 * will always throw an exception; use another overload that allows you to specify the character value instead.
50 * @param keyType Type of the key pressed by this keystroke
52 public KeyStroke(KeyType keyType
) {
53 this(keyType
, false, false);
57 * Constructs a KeyStroke based on a supplied keyType; character will be null.
58 * If you try to construct a KeyStroke with type KeyType.Character with this constructor, it
59 * will always throw an exception; use another overload that allows you to specify the character value instead.
60 * @param keyType Type of the key pressed by this keystroke
61 * @param ctrlDown Was ctrl held down when the main key was pressed?
62 * @param altDown Was alt held down when the main key was pressed?
64 public KeyStroke(KeyType keyType
, boolean ctrlDown
, boolean altDown
) {
65 this(keyType
, null, ctrlDown
, altDown
, false);
69 * Constructs a KeyStroke based on a supplied keyType; character will be null.
70 * If you try to construct a KeyStroke with type KeyType.Character with this constructor, it
71 * will always throw an exception; use another overload that allows you to specify the character value instead.
72 * @param keyType Type of the key pressed by this keystroke
73 * @param ctrlDown Was ctrl held down when the main key was pressed?
74 * @param altDown Was alt held down when the main key was pressed?
75 * @param shiftDown Was shift held down when the main key was pressed?
77 public KeyStroke(KeyType keyType
, boolean ctrlDown
, boolean altDown
, boolean shiftDown
) {
78 this(keyType
, null, ctrlDown
, altDown
, shiftDown
);
82 * Constructs a KeyStroke based on a supplied character, keyType is implicitly KeyType.Character.
84 * A character-based KeyStroke does not support the shiftDown flag, as the shift state has
85 * already been accounted for in the character itself, depending on user's keyboard layout.
86 * @param character Character that was typed on the keyboard
87 * @param ctrlDown Was ctrl held down when the main key was pressed?
88 * @param altDown Was alt held down when the main key was pressed?
90 public KeyStroke(Character character
, boolean ctrlDown
, boolean altDown
) {
91 this(KeyType
.Character
, character
, ctrlDown
, altDown
, false);
94 private KeyStroke(KeyType keyType
, Character character
, boolean ctrlDown
, boolean altDown
, boolean shiftDown
) {
95 if(keyType
== KeyType
.Character
&& character
== null) {
96 throw new IllegalArgumentException("Cannot construct a KeyStroke with type KeyType.Character but no character information");
98 //Enforce character for some key types
111 this.keyType
= keyType
;
112 this.character
= character
;
113 this.shiftDown
= shiftDown
;
114 this.ctrlDown
= ctrlDown
;
115 this.altDown
= altDown
;
116 this.eventTime
= System
.currentTimeMillis();
120 * Type of key that was pressed on the keyboard, as represented by the KeyType enum. If the value if
121 * KeyType.Character, you need to call getCharacter() to find out which letter, number or symbol that was actually
123 * @return Type of key on the keyboard that was pressed
125 public KeyType
getKeyType() {
130 * For keystrokes of ordinary keys (letters, digits, symbols), this method returns the actual character value of the
131 * key. For all other key types, it returns null.
132 * @return Character value of the key pressed, or null if it was a special key
134 public Character
getCharacter() {
139 * @return Returns true if ctrl was help down while the key was typed (depending on terminal implementation)
141 public boolean isCtrlDown() {
146 * @return Returns true if alt was help down while the key was typed (depending on terminal implementation)
148 public boolean isAltDown() {
153 * @return Returns true if shift was help down while the key was typed (depending on terminal implementation)
155 public boolean isShiftDown() {
160 * Gets the time when the keystroke was recorded. This isn't necessarily the time the keystroke happened, but when
161 * Lanterna received the event, so it may not be accurate down to the millisecond.
162 * @return The unix time of when the keystroke happened, in milliseconds
164 public long getEventTime() {
169 public String
toString() {
170 return "KeyStroke{" + "keyType=" + keyType
+ ", character=" + character
+
171 ", ctrlDown=" + ctrlDown
+
172 ", altDown=" + altDown
+
173 ", shiftDown=" + shiftDown
+ '}';
177 public int hashCode() {
179 hash
= 41 * hash
+ (this.keyType
!= null ?
this.keyType
.hashCode() : 0);
180 hash
= 41 * hash
+ (this.character
!= null ?
this.character
.hashCode() : 0);
181 hash
= 41 * hash
+ (this.ctrlDown ?
1 : 0);
182 hash
= 41 * hash
+ (this.altDown ?
1 : 0);
183 hash
= 41 * hash
+ (this.shiftDown ?
1 : 0);
187 @SuppressWarnings("SimplifiableIfStatement")
189 public boolean equals(Object obj
) {
193 if (getClass() != obj
.getClass()) {
196 final KeyStroke other
= (KeyStroke
) obj
;
197 if (this.keyType
!= other
.keyType
) {
200 if (this.character
!= other
.character
&& (this.character
== null || !this.character
.equals(other
.character
))) {
203 return this.ctrlDown
== other
.ctrlDown
&&
204 this.altDown
== other
.altDown
&&
205 this.shiftDown
== other
.shiftDown
;
209 * Creates a Key from a string representation in Vim's key notation.
211 * @param keyStr the string representation of this key
212 * @return the created {@link KeyType}
214 public static KeyStroke
fromString(String keyStr
) {
215 String keyStrLC
= keyStr
.toLowerCase();
217 if (keyStr
.length() == 1) {
218 k
= new KeyStroke(KeyType
.Character
, keyStr
.charAt(0), false, false, false);
219 } else if (keyStr
.startsWith("<") && keyStr
.endsWith(">")) {
220 if (keyStrLC
.equals("<s-tab>")) {
221 k
= new KeyStroke(KeyType
.ReverseTab
);
222 } else if (keyStr
.contains("-")) {
223 ArrayList
<String
> segments
= new ArrayList
<String
>(Arrays
.asList(keyStr
.substring(1, keyStr
.length() - 1).split("-")));
224 if (segments
.size() < 2) {
225 throw new IllegalArgumentException("Invalid vim notation: " + keyStr
);
227 String characterStr
= segments
.remove(segments
.size() - 1);
228 boolean altPressed
= false;
229 boolean ctrlPressed
= false;
230 for (String modifier
: segments
) {
231 if ("c".equals(modifier
.toLowerCase())) {
233 } else if ("a".equals(modifier
.toLowerCase())) {
235 } else if ("s".equals(modifier
.toLowerCase())) {
236 characterStr
= characterStr
.toUpperCase();
239 k
= new KeyStroke(characterStr
.charAt(0), ctrlPressed
, altPressed
);
241 if (keyStrLC
.startsWith("<esc")) {
242 k
= new KeyStroke(KeyType
.Escape
);
243 } else if (keyStrLC
.equals("<cr>") || keyStrLC
.equals("<enter>") || keyStrLC
.equals("<return>")) {
244 k
= new KeyStroke(KeyType
.Enter
);
245 } else if (keyStrLC
.equals("<bs>")) {
246 k
= new KeyStroke(KeyType
.Backspace
);
247 } else if (keyStrLC
.equals("<tab>")) {
248 k
= new KeyStroke(KeyType
.Tab
);
249 } else if (keyStrLC
.equals("<space>")) {
250 k
= new KeyStroke(' ', false, false);
251 } else if (keyStrLC
.equals("<up>")) {
252 k
= new KeyStroke(KeyType
.ArrowUp
);
253 } else if (keyStrLC
.equals("<down>")) {
254 k
= new KeyStroke(KeyType
.ArrowDown
);
255 } else if (keyStrLC
.equals("<left>")) {
256 k
= new KeyStroke(KeyType
.ArrowLeft
);
257 } else if (keyStrLC
.equals("<right>")) {
258 k
= new KeyStroke(KeyType
.ArrowRight
);
259 } else if (keyStrLC
.equals("<insert>")) {
260 k
= new KeyStroke(KeyType
.Insert
);
261 } else if (keyStrLC
.equals("<del>")) {
262 k
= new KeyStroke(KeyType
.Delete
);
263 } else if (keyStrLC
.equals("<home>")) {
264 k
= new KeyStroke(KeyType
.Home
);
265 } else if (keyStrLC
.equals("<end>")) {
266 k
= new KeyStroke(KeyType
.End
);
267 } else if (keyStrLC
.equals("<pageup>")) {
268 k
= new KeyStroke(KeyType
.PageUp
);
269 } else if (keyStrLC
.equals("<pagedown>")) {
270 k
= new KeyStroke(KeyType
.PageDown
);
271 } else if (keyStrLC
.equals("<f1>")) {
272 k
= new KeyStroke(KeyType
.F1
);
273 } else if (keyStrLC
.equals("<f2>")) {
274 k
= new KeyStroke(KeyType
.F2
);
275 } else if (keyStrLC
.equals("<f3>")) {
276 k
= new KeyStroke(KeyType
.F3
);
277 } else if (keyStrLC
.equals("<f4>")) {
278 k
= new KeyStroke(KeyType
.F4
);
279 } else if (keyStrLC
.equals("<f5>")) {
280 k
= new KeyStroke(KeyType
.F5
);
281 } else if (keyStrLC
.equals("<f6>")) {
282 k
= new KeyStroke(KeyType
.F6
);
283 } else if (keyStrLC
.equals("<f7>")) {
284 k
= new KeyStroke(KeyType
.F7
);
285 } else if (keyStrLC
.equals("<f8>")) {
286 k
= new KeyStroke(KeyType
.F8
);
287 } else if (keyStrLC
.equals("<f9>")) {
288 k
= new KeyStroke(KeyType
.F9
);
289 } else if (keyStrLC
.equals("<f10>")) {
290 k
= new KeyStroke(KeyType
.F10
);
291 } else if (keyStrLC
.equals("<f11>")) {
292 k
= new KeyStroke(KeyType
.F11
);
293 } else if (keyStrLC
.equals("<f12>")) {
294 k
= new KeyStroke(KeyType
.F12
);
296 throw new IllegalArgumentException("Invalid vim notation: " + keyStr
);
300 throw new IllegalArgumentException("Invalid vim notation: " + keyStr
);