Reputation: 1599
I am using Selenium with Python and Chrome. I am trying to hold down various keys -- specifically "w, a, s, and d." I have found Selenium's action_chains.key_press action as well as the elem.send_keys method. The problem with the first method is that it only holds the key down for as long as it takes to complete an action chain. The problem with the elem.send_keys method is that it does not have an element to send the keys to.
I am trying to control a web-browser based robot with W-A-S-D, so I need to hold keys down for varying durations.
I have tried the following:
action_chains = ActionChains(driver)
action_chains.key_down("w")
action_chains.key_up("w")
as well as:
action_chains.key_press(elem, "w")
for x in range (0, 100):
action_chains.perform()
time.sleep(.01)
Neither are ideal.
Upvotes: 14
Views: 25846
Reputation: 17
ActionChains(driver).key_down("w").pause(0.1).key_up("w").perform()
By chaining key_down
and key_up
with a .pause(0.1)
in between you can hold down keys for any custom duration.
Even though key_down
should only be used with modifier keys according to the docs, it turns out that it can be used with any key.
Upvotes: 0
Reputation: 42518
The current driver for Chrome (version 2.30) implements the previous protocol where holding a key is only supported for a modifier key (Control, Shift, Alt, Command).
So this code works with Firefox but fails with Chrome since the keyUp
event is emitted for each keyDown
:
action_key_down_w = ActionChains(driver).key_down("w")
action_key_up_w = ActionChains(driver).key_up("w")
endtime = time.time() + 1.0
while True:
action_key_down_w.perform()
if time.time() > endtime:
action_key_up_w.perform()
break
But, since version 2.30, the Chrome driver supports the send_command
to directly send a raw command via the devtools protocol.
So as a workaround, you can call Input.dispatchKeyEvent to emit low level events.
This is a working example with Selenium/Chrome to hold the key w
during a second:
from selenium import webdriver
import json, time
def dispatchKeyEvent(driver, name, options = {}):
options["type"] = name
body = json.dumps({'cmd': 'Input.dispatchKeyEvent', 'params': options})
resource = "/session/%s/chromium/send_command" % driver.session_id
url = driver.command_executor._url + resource
driver.command_executor._request('POST', url, body)
def holdKeyW(driver, duration):
endtime = time.time() + duration
options = { \
"code": "KeyW",
"key": "w",
"text": "w",
"unmodifiedText": "w",
"nativeVirtualKeyCode": ord("W"),
"windowsVirtualKeyCode": ord("W")
}
while True:
dispatchKeyEvent(driver, "rawKeyDown", options)
dispatchKeyEvent(driver, "char", options)
if time.time() > endtime:
dispatchKeyEvent(driver, "keyUp", options)
break
options["autoRepeat"] = True
time.sleep(0.01)
driver = webdriver.Chrome()
driver.get("https://stackoverflow.com/questions")
# set the focus on the targeted element
driver.find_element_by_css_selector("input[name=q]").click()
# press the key W during a second
holdKeyW(driver, 1.0)
Upvotes: 8
Reputation: 6541
According to the Selenium Documentation for key_down
, it states:
Should only be used with modifier keys (Control, Alt and Shift).
I've searched through the docs for an alternative solution, but it appears the behavior to "hold down" non-modifier keys is not possible in Selenium.
Upvotes: 1
Reputation: 5347
Selenium actions chain Should only be used with modifier keys (Control, Alt and Shift). So you want to press only the character w-a-s-d. so that, it didn't work.
You can use any gui automation tools like pyautogui, etc.
please try below code and let me know.
import pyautogui
pyautogui.PAUSE = 10
pyautogui.keyDown('w')
pyautogui.keyUp('w')
pyautogui.PAUSE=10 command make 10 seconds pause after each PyAutoGUI call
Upvotes: 2