Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
SeleniumHQ
GitHub Repository: SeleniumHQ/Selenium
Path: blob/trunk/java/src/org/openqa/selenium/Keys.java
1865 views
1
// Licensed to the Software Freedom Conservancy (SFC) under one
2
// or more contributor license agreements. See the NOTICE file
3
// distributed with this work for additional information
4
// regarding copyright ownership. The SFC licenses this file
5
// to you under the Apache License, Version 2.0 (the
6
// "License"); you may not use this file except in compliance
7
// with the License. You may obtain a copy of the License at
8
//
9
// http://www.apache.org/licenses/LICENSE-2.0
10
//
11
// Unless required by applicable law or agreed to in writing,
12
// software distributed under the License is distributed on an
13
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14
// KIND, either express or implied. See the License for the
15
// specific language governing permissions and limitations
16
// under the License.
17
18
package org.openqa.selenium;
19
20
import java.util.Arrays;
21
import org.jspecify.annotations.NullMarked;
22
import org.jspecify.annotations.Nullable;
23
24
/**
25
* Representations of pressable keys that aren't text. These are stored in the Unicode PUA (Private
26
* Use Area) code points, 0xE000–0xF8FF. These values are used internally by WebDriver to simulate
27
* keyboard input where standard Unicode characters are insufficient, such as modifier and control
28
* keys.
29
*
30
* <p>The codes follow conventions partially established by the W3C WebDriver specification and the
31
* Selenium project. Some values (e.g., RIGHT_SHIFT, RIGHT_COMMAND) are used in ChromeDriver but are
32
* not currently part of the W3C spec. Others (e.g., OPTION, FN) are symbolic and reserved for
33
* possible future mapping.
34
*
35
* <p>For consistency across platforms and drivers, values should be verified before assuming native
36
* support.
37
*
38
* @see <a href="https://www.w3.org/TR/webdriver/#keyboard-actions">W3C WebDriver Keyboard
39
* Actions</a>
40
* @see <a href="http://www.google.com.au/search?&q=unicode+pua&btnK=Search">Unicode PUA
41
* Overview</a>
42
*/
43
@NullMarked
44
public enum Keys implements CharSequence {
45
// Basic control characters
46
NULL('\uE000'),
47
CANCEL('\uE001'), // ^break
48
HELP('\uE002'),
49
BACK_SPACE('\uE003'),
50
TAB('\uE004'),
51
CLEAR('\uE005'),
52
RETURN('\uE006'),
53
ENTER('\uE007'),
54
SHIFT('\uE008'),
55
LEFT_SHIFT(Keys.SHIFT),
56
CONTROL('\uE009'),
57
LEFT_CONTROL(Keys.CONTROL),
58
ALT('\uE00A'),
59
LEFT_ALT(Keys.ALT),
60
PAUSE('\uE00B'),
61
ESCAPE('\uE00C'),
62
SPACE('\uE00D'),
63
PAGE_UP('\uE00E'),
64
PAGE_DOWN('\uE00F'),
65
END('\uE010'),
66
HOME('\uE011'),
67
LEFT('\uE012'),
68
ARROW_LEFT(Keys.LEFT),
69
UP('\uE013'),
70
ARROW_UP(Keys.UP),
71
RIGHT('\uE014'),
72
ARROW_RIGHT(Keys.RIGHT),
73
DOWN('\uE015'),
74
ARROW_DOWN(Keys.DOWN),
75
INSERT('\uE016'),
76
DELETE('\uE017'),
77
SEMICOLON('\uE018'),
78
EQUALS('\uE019'),
79
80
// Number pad keys
81
NUMPAD0('\uE01A'),
82
NUMPAD1('\uE01B'),
83
NUMPAD2('\uE01C'),
84
NUMPAD3('\uE01D'),
85
NUMPAD4('\uE01E'),
86
NUMPAD5('\uE01F'),
87
NUMPAD6('\uE020'),
88
NUMPAD7('\uE021'),
89
NUMPAD8('\uE022'),
90
NUMPAD9('\uE023'),
91
MULTIPLY('\uE024'),
92
ADD('\uE025'),
93
SEPARATOR('\uE026'),
94
SUBTRACT('\uE027'),
95
DECIMAL('\uE028'),
96
DIVIDE('\uE029'),
97
98
// Function keys
99
F1('\uE031'),
100
F2('\uE032'),
101
F3('\uE033'),
102
F4('\uE034'),
103
F5('\uE035'),
104
F6('\uE036'),
105
F7('\uE037'),
106
F8('\uE038'),
107
F9('\uE039'),
108
F10('\uE03A'),
109
F11('\uE03B'),
110
F12('\uE03C'),
111
112
META('\uE03D'),
113
COMMAND(Keys.META),
114
115
// Extended macOS/ChromeDriver keys (based on observed Chrome usage)
116
RIGHT_SHIFT('\uE050'), // aligns with ChromeDriver usage
117
RIGHT_CONTROL('\uE051'),
118
RIGHT_ALT('\uE052'),
119
RIGHT_COMMAND('\uE053'),
120
121
// Symbolic macOS keys not yet standardized
122
OPTION('\uE052'),
123
FN('\uE051'), // TODO: symbolic only; confirm or remove in future
124
125
ZENKAKU_HANKAKU('\uE040');
126
127
private final char keyCode;
128
private final int codePoint;
129
130
Keys(Keys key) {
131
this(key.charAt(0));
132
}
133
134
Keys(char keyCode) {
135
this.keyCode = keyCode;
136
this.codePoint = String.valueOf(keyCode).codePoints().findFirst().getAsInt();
137
}
138
139
public int getCodePoint() {
140
return codePoint;
141
}
142
143
@Override
144
public char charAt(int index) {
145
if (index == 0) {
146
return keyCode;
147
}
148
return 0;
149
}
150
151
@Override
152
public int length() {
153
return 1;
154
}
155
156
@Override
157
public CharSequence subSequence(int start, int end) {
158
if (start == 0 && end == 1) {
159
return String.valueOf(keyCode);
160
}
161
throw new IndexOutOfBoundsException();
162
}
163
164
@Override
165
public String toString() {
166
return String.valueOf(keyCode);
167
}
168
169
/**
170
* Simulate pressing many keys at once in a "chord". Takes a sequence of Keys.XXXX or strings;
171
* appends each to a string, adds the chord termination key (Keys.NULL), and returns it.
172
*
173
* <p>Note: Keys.NULL signals release of modifier keys like CTRL/ALT/SHIFT via keyup events.
174
*
175
* @param value characters to send
176
* @return String representation of the char sequence
177
*/
178
public static String chord(CharSequence... value) {
179
return chord(Arrays.asList(value));
180
}
181
182
/**
183
* Overload of {@link #chord(CharSequence...)} that accepts an iterable.
184
*
185
* @param value characters to send
186
* @return String representation of the char sequence
187
*/
188
public static String chord(Iterable<CharSequence> value) {
189
StringBuilder builder = new StringBuilder();
190
for (CharSequence seq : value) {
191
builder.append(seq);
192
}
193
builder.append(Keys.NULL);
194
return builder.toString();
195
}
196
197
/**
198
* Retrieves the {@link Keys} enum constant corresponding to the given Unicode character.
199
*
200
* @param key unicode character code
201
* @return special key linked to the character code, or null if not found
202
*/
203
public static @Nullable Keys getKeyFromUnicode(char key) {
204
for (Keys unicodeKey : values()) {
205
if (unicodeKey.charAt(0) == key) {
206
return unicodeKey;
207
}
208
}
209
return null;
210
}
211
}
212
213