1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286
|
"""
Keyboard input.
This module contains a class implementing pygame keyboard input.
"""
__author__ = 'Florian Krause <florian@expyriment.org>, \
Oliver Lindemann <oliver@expyriment.org>'
__version__ = '0.7.0'
__revision__ = '55a4e7e'
__date__ = 'Wed Mar 26 14:33:37 2014 +0100'
import time, sys
import pygame
try:
import android.show_keyboard as android_show_keyboard
import android.hide_keyboard as android_hide_keyboard
except ImportError:
android_show_keyboard = android_hide_keyboard = None
import defaults
import expyriment
from expyriment.misc._timer import get_time
from _input_output import Input
quit_key = None
pause_key = None
end_function = None
pause_function = None
class Keyboard(Input):
"""A class implementing a keyboard input.
Calling `expyriment.control.intialize(exp)` will automatically create a
keyboard instance and will reference it in exp.keyboard for easy access.
"""
@staticmethod
def process_control_keys(key_event=None):
"""Check if quit_key or pause_key has been pressed.
Reads pygame event cue if no key_event is specified.
Parameters
----------
key_event : int, optional
key event to check
Returns
-------
out : bool
True if quitting or pause screen has been displayed,
False otherwise
"""
if key_event:
if key_event.type == pygame.KEYDOWN:
if key_event.key == quit_key and \
end_function is not None:
confirm = end_function(confirmation=True)
if confirm:
sys.exit()
return True
elif key_event.key == pause_key and \
pause_function is not None:
pause_function()
return True
else:
for event in pygame.event.get(pygame.KEYDOWN):
return Keyboard.process_control_keys(event) # recursive
return False
def __init__(self, default_keys=None):
"""Create a keyboard input.
Parameters
----------
default_keys : int or list, optional
a default key or list of default keys
"""
if default_keys is not None:
self._default_keys = default_keys
else:
self._default_keys = defaults.keyboard_default_keys
Input.__init__(self)
@property
def default_keys(self):
"""Getter for default keys"""
return self._default_keys
@default_keys.setter
def default_keys(self, value):
"""Setter for default keys"""
self._default_keys = value
def clear(self):
"""Clear the event queue from keyboard events."""
pygame.event.clear(pygame.KEYDOWN)
pygame.event.clear(pygame.KEYUP)
if self._logging:
expyriment._active_exp._event_file_log("Keyboard,cleared", 2)
def read_out_buffered_keys(self):
"""Reads out all keydown events and clears queue."""
pygame.event.pump()
pygame.event.clear(pygame.KEYUP)
rtn = []
for event in pygame.event.get(pygame.KEYDOWN):
Keyboard.process_control_keys(event)
rtn.append(event.key)
return rtn
def check(self, keys=None, check_for_control_keys=True):
"""Check if keypress is in event queue.
Parameters
----------
keys : int or list, optional
a specific key or list of keys to check
check_for_control_keys : bool, optional
checks if control key has been pressed (default=True)
Returns
-------
key : int
pressed key or None. Only the first occurence is returned!
"""
if keys is None:
keys = self.default_keys
if type(keys) is not list and keys is not None:
keys = [keys]
pygame.event.pump()
pygame.event.clear(pygame.KEYUP)
for event in pygame.event.get(pygame.KEYDOWN):
if check_for_control_keys:
Keyboard.process_control_keys(event)
if keys:
if event.key in keys:
if self._logging:
expyriment._active_exp._event_file_log(
"Keyboard,received,{0},check".format(event.key))
return event.key
else:
if self._logging:
expyriment._active_exp._event_file_log(
"Keyboard,received,{0},check".format(event.key), 2)
return event.key
return None
def wait(self, keys=None, duration=None, wait_for_keyup=False,
check_for_control_keys=True):
"""Wait for keypress(es) (optionally for a certain amount of time).
This function will wait for a keypress and returns the found key as
well as the reaction time.
(This function clears the event queue!)
Parameters
----------
keys : int or list, optional
a specific key or list of keys to wait for
duration : int, optional
maximal time to wait in ms
wait_for_keyup : bool, optional
if True it waits for key-up
check_for_control_keys : bool, optional
checks if control key has been pressed (default=True)
Returns
-------
found : char
pressed charater
rt : int
reaction time in ms
"""
if android_show_keyboard is not None:
android_show_keyboard()
start = get_time()
rt = None
found_key = None
self.clear()
if keys is None:
keys = self.default_keys
if keys is not None and type(keys) is not list:
keys = [keys]
if wait_for_keyup:
target_event = pygame.KEYUP
else:
target_event = pygame.KEYDOWN
pygame.event.pump()
done = False
while not done:
expyriment._active_exp._execute_wait_callback()
for event in pygame.event.get():
if check_for_control_keys and Keyboard.process_control_keys(event):
done = True
elif event.type == target_event:
if keys is not None:
if event.key in keys:
rt = int((get_time() - start) * 1000)
found_key = event.key
done = True
else:
rt = int((get_time() - start) * 1000)
found_key = event.key
done = True
if duration and not done:
done = int((get_time() - start) * 1000) >= duration
time.sleep(0.0005)
if self._logging:
expyriment._active_exp._event_file_log("Keyboard,received,{0},wait"\
.format(found_key))
if android_hide_keyboard is not None:
android_hide_keyboard()
return found_key, rt
def wait_char(self, char, duration=None, check_for_control_keys=True):
"""Wait for character(s) (optionally for a certain amount of time).
This function will wait for one or more characters and returns the
found character as well as the reaction time.
(This function clears the event queue!)
Parameters
----------
char : int or list
a specific character or list of characters to wait for
duration : int, optional
maximal time to wait in ms
check_for_control_keys : bool, optional
checks if control key has been pressed (default=True)
Returns
-------
found : char
pressed charater
rt : int
reaction time in ms
"""
start = get_time()
rt = None
found_char = None
self.clear()
if type(char) is not list:
char = [char]
pygame.event.pump()
done = False
while not done:
expyriment._active_exp._execute_wait_callback()
for event in pygame.event.get():
if check_for_control_keys and Keyboard.process_control_keys(event):
done = True
elif event.type == pygame.KEYDOWN:
if event.unicode in char:
rt = int((get_time() - start) * 1000)
found_char = event.unicode
done = True
if duration and not done:
done = int((get_time() - start) * 1000) >= duration
time.sleep(0.0005)
if self._logging:
expyriment._active_exp._event_file_log(
"Keyboard,received,{0},wait_char".format(found_char))
return found_char, rt
|