1 | /* |
2 | * Copyright (C) 2018, 2019 Apple Inc. All rights reserved. |
3 | * |
4 | * Redistribution and use in source and binary forms, with or without |
5 | * modification, are permitted provided that the following conditions |
6 | * are met: |
7 | * 1. Redistributions of source code must retain the above copyright |
8 | * notice, this list of conditions and the following disclaimer. |
9 | * 2. Redistributions in binary form must reproduce the above copyright |
10 | * notice, this list of conditions and the following disclaimer in the |
11 | * documentation and/or other materials provided with the distribution. |
12 | * |
13 | * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' |
14 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, |
15 | * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
16 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS |
17 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
18 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
19 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
20 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
21 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
22 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF |
23 | * THE POSSIBILITY OF SUCH DAMAGE. |
24 | */ |
25 | |
26 | #pragma once |
27 | |
28 | #if ENABLE(WEBDRIVER_ACTIONS_API) |
29 | |
30 | #include "WebEvent.h" |
31 | #include <wtf/CompletionHandler.h> |
32 | #include <wtf/HashSet.h> |
33 | #include <wtf/Optional.h> |
34 | #include <wtf/RefCounted.h> |
35 | #include <wtf/RunLoop.h> |
36 | #include <wtf/Seconds.h> |
37 | #include <wtf/Vector.h> |
38 | #include <wtf/text/WTFString.h> |
39 | |
40 | namespace Inspector { namespace Protocol { namespace Automation { |
41 | enum class ErrorMessage; |
42 | enum class KeyboardInteractionType; |
43 | enum class MouseInteraction; |
44 | enum class MouseMoveOrigin; |
45 | enum class VirtualKey; |
46 | } } } |
47 | |
48 | namespace WebKit { |
49 | |
50 | class AutomationCommandError; |
51 | using AutomationCompletionHandler = WTF::CompletionHandler<void(Optional<AutomationCommandError>)>; |
52 | |
53 | class WebPageProxy; |
54 | |
55 | using KeyboardInteraction = Inspector::Protocol::Automation::KeyboardInteractionType; |
56 | using VirtualKey = Inspector::Protocol::Automation::VirtualKey; |
57 | using VirtualKeySet = HashSet<VirtualKey, WTF::IntHash<VirtualKey>, WTF::StrongEnumHashTraits<VirtualKey>>; |
58 | using CharKey = char; // For WebDriver, this only needs to support ASCII characters on 102-key keyboard. |
59 | using MouseButton = WebMouseEvent::Button; |
60 | using MouseInteraction = Inspector::Protocol::Automation::MouseInteraction; |
61 | using MouseMoveOrigin = Inspector::Protocol::Automation::MouseMoveOrigin; |
62 | |
63 | enum class SimulatedInputSourceType { |
64 | Null, // Used to induce a minimum duration. |
65 | Keyboard, |
66 | Mouse, |
67 | Touch, |
68 | }; |
69 | |
70 | enum class TouchInteraction { |
71 | TouchDown, |
72 | MoveTo, |
73 | LiftUp, |
74 | }; |
75 | |
76 | struct SimulatedInputSourceState { |
77 | Optional<CharKey> pressedCharKey; |
78 | VirtualKeySet pressedVirtualKeys; |
79 | Optional<MouseButton> pressedMouseButton; |
80 | Optional<MouseMoveOrigin> origin; |
81 | Optional<String> nodeHandle; |
82 | Optional<WebCore::IntPoint> location; |
83 | Optional<Seconds> duration; |
84 | |
85 | static SimulatedInputSourceState emptyStateForSourceType(SimulatedInputSourceType); |
86 | }; |
87 | |
88 | struct SimulatedInputSource : public RefCounted<SimulatedInputSource> { |
89 | public: |
90 | SimulatedInputSourceType type; |
91 | |
92 | // The last state associated with this input source. |
93 | SimulatedInputSourceState state; |
94 | |
95 | static Ref<SimulatedInputSource> create(SimulatedInputSourceType type) |
96 | { |
97 | return adoptRef(*new SimulatedInputSource(type)); |
98 | } |
99 | |
100 | private: |
101 | SimulatedInputSource(SimulatedInputSourceType type) |
102 | : type(type) |
103 | , state(SimulatedInputSourceState::emptyStateForSourceType(type)) |
104 | { } |
105 | }; |
106 | |
107 | struct SimulatedInputKeyFrame { |
108 | public: |
109 | using StateEntry = std::pair<SimulatedInputSource&, SimulatedInputSourceState>; |
110 | |
111 | explicit SimulatedInputKeyFrame(Vector<StateEntry>&&); |
112 | Seconds maximumDuration() const; |
113 | |
114 | static SimulatedInputKeyFrame keyFrameFromStateOfInputSources(HashSet<Ref<SimulatedInputSource>>&); |
115 | static SimulatedInputKeyFrame keyFrameToResetInputSources(HashSet<Ref<SimulatedInputSource>>&); |
116 | |
117 | Vector<StateEntry> states; |
118 | }; |
119 | |
120 | class SimulatedInputDispatcher : public RefCounted<SimulatedInputDispatcher> { |
121 | WTF_MAKE_NONCOPYABLE(SimulatedInputDispatcher); |
122 | public: |
123 | class Client { |
124 | public: |
125 | virtual ~Client() { } |
126 | #if ENABLE(WEBDRIVER_MOUSE_INTERACTIONS) |
127 | virtual void simulateMouseInteraction(WebPageProxy&, MouseInteraction, WebMouseEvent::Button, const WebCore::IntPoint& locationInView, AutomationCompletionHandler&&) = 0; |
128 | #endif |
129 | #if ENABLE(WEBDRIVER_TOUCH_INTERACTIONS) |
130 | virtual void simulateTouchInteraction(WebPageProxy&, TouchInteraction, const WebCore::IntPoint& locationInView, Optional<Seconds> duration, AutomationCompletionHandler&&) = 0; |
131 | #endif |
132 | #if ENABLE(WEBDRIVER_KEYBOARD_INTERACTIONS) |
133 | virtual void simulateKeyboardInteraction(WebPageProxy&, KeyboardInteraction, WTF::Variant<VirtualKey, CharKey>&&, AutomationCompletionHandler&&) = 0; |
134 | #endif |
135 | virtual void viewportInViewCenterPointOfElement(WebPageProxy&, uint64_t frameID, const String& nodeHandle, Function<void (Optional<WebCore::IntPoint>, Optional<AutomationCommandError>)>&&) = 0; |
136 | }; |
137 | |
138 | static Ref<SimulatedInputDispatcher> create(WebPageProxy& page, SimulatedInputDispatcher::Client& client) |
139 | { |
140 | return adoptRef(*new SimulatedInputDispatcher(page, client)); |
141 | } |
142 | |
143 | ~SimulatedInputDispatcher(); |
144 | |
145 | void run(uint64_t frameID, Vector<SimulatedInputKeyFrame>&& keyFrames, HashSet<Ref<SimulatedInputSource>>& inputSources, AutomationCompletionHandler&&); |
146 | void cancel(); |
147 | |
148 | bool isActive() const; |
149 | |
150 | private: |
151 | SimulatedInputDispatcher(WebPageProxy&, SimulatedInputDispatcher::Client&); |
152 | |
153 | void transitionToNextKeyFrame(); |
154 | void transitionBetweenKeyFrames(const SimulatedInputKeyFrame&, const SimulatedInputKeyFrame&, AutomationCompletionHandler&&); |
155 | |
156 | void transitionToNextInputSourceState(); |
157 | void transitionInputSourceToState(SimulatedInputSource&, SimulatedInputSourceState& newState, AutomationCompletionHandler&&); |
158 | void finishDispatching(Optional<AutomationCommandError>); |
159 | |
160 | void keyFrameTransitionDurationTimerFired(); |
161 | bool isKeyFrameTransitionComplete() const; |
162 | |
163 | void resolveLocation(const WebCore::IntPoint& currentLocation, Optional<WebCore::IntPoint> location, MouseMoveOrigin, Optional<String> nodeHandle, Function<void (Optional<WebCore::IntPoint>, Optional<AutomationCommandError>)>&&); |
164 | |
165 | WebPageProxy& m_page; |
166 | SimulatedInputDispatcher::Client& m_client; |
167 | |
168 | Optional<uint64_t> m_frameID; |
169 | AutomationCompletionHandler m_runCompletionHandler; |
170 | AutomationCompletionHandler m_keyFrameTransitionCompletionHandler; |
171 | RunLoop::Timer<SimulatedInputDispatcher> m_keyFrameTransitionDurationTimer; |
172 | |
173 | Vector<SimulatedInputKeyFrame> m_keyframes; |
174 | HashSet<Ref<SimulatedInputSource>> m_inputSources; |
175 | |
176 | // The position within m_keyframes. |
177 | unsigned m_keyframeIndex { 0 }; |
178 | |
179 | // The position within the input source state vector at m_keyframes[m_keyframeIndex]. |
180 | // Events that reflect input source state transitions are dispatched serially based on this order. |
181 | unsigned m_inputSourceStateIndex { 0 }; |
182 | }; |
183 | |
184 | } // namespace WebKit |
185 | |
186 | #endif // ENABLE(WEBDRIVER_ACTIONS_API) |
187 | |