// Copyright 2015 Google Inc. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. import 'dart:async'; import '../common/mouse.dart'; import '../common/request_client.dart'; import '../common/webdriver_handler.dart'; import '../handler/json_wire_handler.dart'; import '../handler/w3c_handler.dart'; import 'web_element.dart'; class Mouse { final AsyncRequestClient _client; final WebDriverHandler _handler; Mouse(this._client, this._handler); /// Click any mouse button (at the coordinates set by the last moveTo). Future click([MouseButton button = MouseButton.primary]) => _client.send(_handler.mouse.buildClickRequest(button), _handler.mouse.parseClickResponse); /// Click and hold any mouse button (at the coordinates set by the last /// moveTo command). Future down([MouseButton button = MouseButton.primary]) => _client.send( _handler.mouse.buildDownRequest(button), _handler.mouse.parseDownResponse); /// Releases the mouse button previously held (where the mouse is currently at). Future up([MouseButton button = MouseButton.primary]) => _client.send( _handler.mouse.buildUpRequest(button), _handler.mouse.parseUpResponse); /// Double-clicks at the current mouse coordinates (set by moveTo). Future doubleClick() => _client.send( _handler.mouse.buildDoubleClickRequest(), _handler.mouse.parseDoubleClickResponse); /// Move the mouse. /// /// If [element] is specified and [xOffset] and [yOffset] are not, will move /// the mouse to the center of the [element]. /// /// If [xOffset] and [yOffset] are specified, will move the mouse that distance /// from its current location. /// /// If all three are specified, the behavior will be different /// for W3C and JsonWire. For W3C, it will use [element] center as the /// origin, while for JsonWire, it will use [element] top left corner. /// To get a consistent behavior across browsers, you can try /// [moveToElementCenter] and [moveToElementTopLeft] to specify the origin you /// would like to use. /// /// All other combinations of parameters are illegal. /// /// Special notes for W3C, if the destination is out of the current viewport, /// an 'MoveTargetOutOfBounds' exception will be thrown. Future moveTo( {WebElement? element, int? xOffset, int? yOffset, bool absolute = false}) => _client.send( _handler.mouse.buildMoveToRequest( elementId: element?.id, xOffset: xOffset, yOffset: yOffset, absolute: absolute), _handler.mouse.parseMoveToResponse); /// Moves to [element], with an offset of [xOffset] and [yOffset] based on the /// center of [element]. Future moveToElementCenter(WebElement element, {int? xOffset, int? yOffset}) async { if (_handler is JsonWireWebDriverHandler) { final size = await element.size; await moveTo( element: element, xOffset: (xOffset ?? 0) + size.width ~/ 2, yOffset: (yOffset ?? 0) + size.height ~/ 2); } else { await moveTo(element: element, xOffset: xOffset, yOffset: yOffset); } } /// Moves to [element], with an offset of [xOffset] and [yOffset] based on the /// top left corner of [element]. Future moveToElementTopLeft(WebElement element, {int? xOffset, int? yOffset}) async { if (_handler is W3cWebDriverHandler) { final size = await element.size; await moveTo( element: element, xOffset: (xOffset ?? 0) - size.width ~/ 2, yOffset: (yOffset ?? 0) - size.height ~/ 2); } else { await moveTo(element: element, xOffset: xOffset, yOffset: yOffset); } } /// Moves the mouse away to hide its effect, like hover over element. /// /// For W3C, the mouse cannot move out of the screen, the workaround would be /// to move to somewhere on edge where it's not on any element. You can /// configure the location with [w3cXOffset] and [w3cYOffset]. By default, /// it's at (100, 0). Future hide({int w3cXOffset = 100, int w3cYOffset = 0}) => _handler is W3cWebDriverHandler ? moveTo(xOffset: w3cXOffset, yOffset: w3cYOffset, absolute: true) : moveTo(xOffset: -10000, yOffset: -10000); @override String toString() => '$_handler.mouse($_client)'; @override int get hashCode => _client.hashCode; @override bool operator ==(Object other) => other is Mouse && _handler == other._handler && _client == other._client; }