Skip to content

Commit 6a7d567

Browse files
authored
Split input classes (#2577)
1 parent c43ee44 commit 6a7d567

File tree

7 files changed

+794
-641
lines changed

7 files changed

+794
-641
lines changed
Lines changed: 229 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,229 @@
1+
// * MIT License
2+
// *
3+
// * Copyright (c) Darío Kondratiuk
4+
// *
5+
// * Permission is hereby granted, free of charge, to any person obtaining a copy
6+
// * of this software and associated documentation files (the "Software"), to deal
7+
// * in the Software without restriction, including without limitation the rights
8+
// * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
// * copies of the Software, and to permit persons to whom the Software is
10+
// * furnished to do so, subject to the following conditions:
11+
// *
12+
// * The above copyright notice and this permission notice shall be included in all
13+
// * copies or substantial portions of the Software.
14+
// *
15+
// * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
// * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
// * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
// * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
// * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
// * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
// * SOFTWARE.
22+
23+
using System.Collections.Generic;
24+
using System.Globalization;
25+
using System.Threading.Tasks;
26+
using PuppeteerSharp.Cdp.Messaging;
27+
using PuppeteerSharp.Input;
28+
29+
namespace PuppeteerSharp.Cdp;
30+
31+
/// <inheritdoc/>
32+
public class CdpKeyboard : Keyboard
33+
{
34+
private readonly HashSet<string> _pressedKeys = [];
35+
private CDPSession _client;
36+
37+
internal CdpKeyboard(CDPSession client)
38+
{
39+
_client = client;
40+
}
41+
42+
/// <inheritdoc/>
43+
public override Task DownAsync(string key, DownOptions options = null)
44+
{
45+
var description = KeyDescriptionForString(key);
46+
47+
var autoRepeat = _pressedKeys.Contains(description.Code);
48+
_pressedKeys.Add(description.Code);
49+
Modifiers |= ModifierBit(key);
50+
51+
var text = options?.Text == null ? description.Text : options.Text;
52+
53+
return _client.SendAsync("Input.dispatchKeyEvent", new InputDispatchKeyEventRequest
54+
{
55+
Type = text != null ? DispatchKeyEventType.KeyDown : DispatchKeyEventType.RawKeyDown,
56+
Modifiers = Modifiers,
57+
WindowsVirtualKeyCode = description.KeyCode,
58+
Code = description.Code,
59+
Key = description.Key,
60+
Text = text,
61+
UnmodifiedText = text,
62+
AutoRepeat = autoRepeat,
63+
Location = description.Location,
64+
IsKeypad = description.Location == 3,
65+
});
66+
}
67+
68+
/// <inheritdoc/>
69+
public override Task UpAsync(string key)
70+
{
71+
var description = KeyDescriptionForString(key);
72+
73+
Modifiers &= ~ModifierBit(key);
74+
_pressedKeys.Remove(description.Code);
75+
76+
return _client.SendAsync("Input.dispatchKeyEvent", new InputDispatchKeyEventRequest
77+
{
78+
Type = DispatchKeyEventType.KeyUp,
79+
Modifiers = Modifiers,
80+
Key = description.Key,
81+
WindowsVirtualKeyCode = description.KeyCode,
82+
Code = description.Code,
83+
Location = description.Location,
84+
});
85+
}
86+
87+
/// <inheritdoc/>
88+
public override Task SendCharacterAsync(string charText)
89+
=> _client.SendAsync("Input.insertText", new InputInsertTextRequest
90+
{
91+
Text = charText,
92+
});
93+
94+
/// <inheritdoc/>
95+
public override async Task TypeAsync(string text, TypeOptions options = null)
96+
{
97+
var delay = 0;
98+
if (options?.Delay != null)
99+
{
100+
delay = (int)options.Delay;
101+
}
102+
103+
var textParts = StringInfo.GetTextElementEnumerator(text);
104+
while (textParts.MoveNext())
105+
{
106+
var letter = textParts.Current;
107+
if (KeyDefinitions.ContainsKey(letter.ToString()))
108+
{
109+
await PressAsync(letter.ToString(), new PressOptions { Delay = delay }).ConfigureAwait(false);
110+
}
111+
else
112+
{
113+
if (delay > 0)
114+
{
115+
await Task.Delay(delay).ConfigureAwait(false);
116+
}
117+
118+
await SendCharacterAsync(letter.ToString()).ConfigureAwait(false);
119+
}
120+
}
121+
}
122+
123+
/// <inheritdoc/>
124+
public override async Task PressAsync(string key, PressOptions options = null)
125+
{
126+
await DownAsync(key, options).ConfigureAwait(false);
127+
if (options?.Delay > 0)
128+
{
129+
await Task.Delay((int)options.Delay).ConfigureAwait(false);
130+
}
131+
132+
await UpAsync(key).ConfigureAwait(false);
133+
}
134+
135+
internal void UpdateClient(CDPSession newSession) => _client = newSession;
136+
137+
private int ModifierBit(string key)
138+
{
139+
if (key == "Alt")
140+
{
141+
return 1;
142+
}
143+
144+
if (key == "Control")
145+
{
146+
return 2;
147+
}
148+
149+
if (key == "Meta")
150+
{
151+
return 4;
152+
}
153+
154+
if (key == "Shift")
155+
{
156+
return 8;
157+
}
158+
159+
return 0;
160+
}
161+
162+
private KeyDefinition KeyDescriptionForString(string keyString)
163+
{
164+
var shift = Modifiers & 8;
165+
var description = new KeyDefinition
166+
{
167+
Key = string.Empty,
168+
KeyCode = 0,
169+
Code = string.Empty,
170+
Text = string.Empty,
171+
Location = 0,
172+
};
173+
174+
var definition = KeyDefinitions.Get(keyString);
175+
176+
if (!string.IsNullOrEmpty(definition.Key))
177+
{
178+
description.Key = definition.Key;
179+
}
180+
181+
if (shift > 0 && !string.IsNullOrEmpty(definition.ShiftKey))
182+
{
183+
description.Key = definition.ShiftKey;
184+
}
185+
186+
if (definition.KeyCode > 0)
187+
{
188+
description.KeyCode = definition.KeyCode;
189+
}
190+
191+
if (shift > 0 && definition.ShiftKeyCode != null)
192+
{
193+
description.KeyCode = (int)definition.ShiftKeyCode;
194+
}
195+
196+
if (!string.IsNullOrEmpty(definition.Code))
197+
{
198+
description.Code = definition.Code;
199+
}
200+
201+
if (definition.Location != 0)
202+
{
203+
description.Location = definition.Location;
204+
}
205+
206+
if (description.Key.Length == 1)
207+
{
208+
description.Text = description.Key;
209+
}
210+
211+
if (!string.IsNullOrEmpty(definition.Text))
212+
{
213+
description.Text = definition.Text;
214+
}
215+
216+
if (shift > 0 && !string.IsNullOrEmpty(definition.ShiftText))
217+
{
218+
description.Text = definition.ShiftText;
219+
}
220+
221+
// if any modifiers besides shift are pressed, no text should be sent
222+
if ((Modifiers & ~8) > 0)
223+
{
224+
description.Text = string.Empty;
225+
}
226+
227+
return description;
228+
}
229+
}

0 commit comments

Comments
 (0)