psychopy 2024.2.5__py3-none-any.whl → 2025.1.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of psychopy might be problematic. Click here for more details.
- psychopy/CHANGELOG.txt +4 -4
- psychopy/GIT_SHA +1 -1
- psychopy/LICENSE.txt +1 -1
- psychopy/VERSION +1 -1
- psychopy/__init__.py +10 -7
- psychopy/alerts/__init__.py +1 -1
- psychopy/alerts/_alerts.py +53 -17
- psychopy/alerts/_errorHandler.py +3 -4
- psychopy/alerts/alertsCatalogue/3210.yaml +27 -0
- psychopy/alerts/alertsCatalogue/3610.yaml +19 -0
- psychopy/alerts/alertsCatalogue/4130.yaml +19 -0
- psychopy/alerts/alertsCatalogue/alertCategories.yaml +8 -1
- psychopy/alerts/alertsCatalogue/alertmsg.py +1 -1
- psychopy/alerts/alerttools.py +0 -16
- psychopy/app/Resources/betasplash.png +0 -0
- psychopy/app/Resources/betasplash@2x.png +0 -0
- psychopy/app/Resources/classic/case.png +0 -0
- psychopy/app/Resources/classic/case@2x.png +0 -0
- psychopy/app/Resources/classic/fileaudio.png +0 -0
- psychopy/app/Resources/classic/fileaudio@2x.png +0 -0
- psychopy/app/Resources/classic/filecss.png +0 -0
- psychopy/app/Resources/classic/filecss@2x.png +0 -0
- psychopy/app/Resources/classic/filecsv.png +0 -0
- psychopy/app/Resources/classic/filecsv@2x.png +0 -0
- psychopy/app/Resources/classic/filedesign.png +0 -0
- psychopy/app/Resources/classic/filedesign@2x.png +0 -0
- psychopy/app/Resources/classic/filefont.png +0 -0
- psychopy/app/Resources/classic/filefont@2x.png +0 -0
- psychopy/app/Resources/classic/filegit.png +0 -0
- psychopy/app/Resources/classic/filegit@2x.png +0 -0
- psychopy/app/Resources/classic/filehtml.png +0 -0
- psychopy/app/Resources/classic/filehtml@2x.png +0 -0
- psychopy/app/Resources/classic/fileimage.png +0 -0
- psychopy/app/Resources/classic/fileimage@2x.png +0 -0
- psychopy/app/Resources/classic/fileinfo.png +0 -0
- psychopy/app/Resources/classic/fileinfo@2x.png +0 -0
- psychopy/app/Resources/classic/filejs.png +0 -0
- psychopy/app/Resources/classic/filejs@2x.png +0 -0
- psychopy/app/Resources/classic/filejson.png +0 -0
- psychopy/app/Resources/classic/filejson@2x.png +0 -0
- psychopy/app/Resources/classic/filepkg.png +0 -0
- psychopy/app/Resources/classic/filepkg@2x.png +0 -0
- psychopy/app/Resources/classic/filepsyexp.png +0 -0
- psychopy/app/Resources/classic/filepsyexp@2x.png +0 -0
- psychopy/app/Resources/classic/filepy.png +0 -0
- psychopy/app/Resources/classic/filepy@2x.png +0 -0
- psychopy/app/Resources/classic/filetxt.png +0 -0
- psychopy/app/Resources/classic/filetxt@2x.png +0 -0
- psychopy/app/Resources/classic/fileunknown.png +0 -0
- psychopy/app/Resources/classic/fileunknown@2x.png +0 -0
- psychopy/app/Resources/classic/filevideo.png +0 -0
- psychopy/app/Resources/classic/filevideo@2x.png +0 -0
- psychopy/app/Resources/classic/find.png +0 -0
- psychopy/app/Resources/classic/find@2x.png +0 -0
- psychopy/app/Resources/classic/loop.png +0 -0
- psychopy/app/Resources/classic/loop@2x.png +0 -0
- psychopy/app/Resources/classic/regex.png +0 -0
- psychopy/app/Resources/classic/regex@2x.png +0 -0
- psychopy/app/Resources/dark/case.png +0 -0
- psychopy/app/Resources/dark/case@2x.png +0 -0
- psychopy/app/Resources/dark/fileaudio.png +0 -0
- psychopy/app/Resources/dark/fileaudio@2x.png +0 -0
- psychopy/app/Resources/dark/filecss.png +0 -0
- psychopy/app/Resources/dark/filecss@2x.png +0 -0
- psychopy/app/Resources/dark/filecsv.png +0 -0
- psychopy/app/Resources/dark/filecsv@2x.png +0 -0
- psychopy/app/Resources/dark/filedesign.png +0 -0
- psychopy/app/Resources/dark/filedesign@2x.png +0 -0
- psychopy/app/Resources/dark/filefont.png +0 -0
- psychopy/app/Resources/dark/filefont@2x.png +0 -0
- psychopy/app/Resources/dark/filegit.png +0 -0
- psychopy/app/Resources/dark/filegit@2x.png +0 -0
- psychopy/app/Resources/dark/filehtml.png +0 -0
- psychopy/app/Resources/dark/filehtml@2x.png +0 -0
- psychopy/app/Resources/dark/fileimage.png +0 -0
- psychopy/app/Resources/dark/fileimage@2x.png +0 -0
- psychopy/app/Resources/dark/fileinfo.png +0 -0
- psychopy/app/Resources/dark/fileinfo@2x.png +0 -0
- psychopy/app/Resources/dark/filejs.png +0 -0
- psychopy/app/Resources/dark/filejs@2x.png +0 -0
- psychopy/app/Resources/dark/filejson.png +0 -0
- psychopy/app/Resources/dark/filejson@2x.png +0 -0
- psychopy/app/Resources/dark/filepkg.png +0 -0
- psychopy/app/Resources/dark/filepkg@2x.png +0 -0
- psychopy/app/Resources/dark/filepsyexp.png +0 -0
- psychopy/app/Resources/dark/filepsyexp@2x.png +0 -0
- psychopy/app/Resources/dark/filepy.png +0 -0
- psychopy/app/Resources/dark/filepy@2x.png +0 -0
- psychopy/app/Resources/dark/filetxt.png +0 -0
- psychopy/app/Resources/dark/filetxt@2x.png +0 -0
- psychopy/app/Resources/dark/fileunknown.png +0 -0
- psychopy/app/Resources/dark/fileunknown@2x.png +0 -0
- psychopy/app/Resources/dark/filevideo.png +0 -0
- psychopy/app/Resources/dark/filevideo@2x.png +0 -0
- psychopy/app/Resources/dark/find.png +0 -0
- psychopy/app/Resources/dark/find@2x.png +0 -0
- psychopy/app/Resources/dark/loop.png +0 -0
- psychopy/app/Resources/dark/loop@2x.png +0 -0
- psychopy/app/Resources/dark/regex.png +0 -0
- psychopy/app/Resources/dark/regex@2x.png +0 -0
- psychopy/app/Resources/light/case.png +0 -0
- psychopy/app/Resources/light/case@2x.png +0 -0
- psychopy/app/Resources/light/fileaudio.png +0 -0
- psychopy/app/Resources/light/fileaudio@2x.png +0 -0
- psychopy/app/Resources/light/filecss.png +0 -0
- psychopy/app/Resources/light/filecss@2x.png +0 -0
- psychopy/app/Resources/light/filecsv.png +0 -0
- psychopy/app/Resources/light/filecsv@2x.png +0 -0
- psychopy/app/Resources/light/filedesign.png +0 -0
- psychopy/app/Resources/light/filedesign@2x.png +0 -0
- psychopy/app/Resources/light/filefont.png +0 -0
- psychopy/app/Resources/light/filefont@2x.png +0 -0
- psychopy/app/Resources/light/filegit.png +0 -0
- psychopy/app/Resources/light/filegit@2x.png +0 -0
- psychopy/app/Resources/light/filehtml.png +0 -0
- psychopy/app/Resources/light/filehtml@2x.png +0 -0
- psychopy/app/Resources/light/fileimage.png +0 -0
- psychopy/app/Resources/light/fileimage@2x.png +0 -0
- psychopy/app/Resources/light/fileinfo.png +0 -0
- psychopy/app/Resources/light/fileinfo@2x.png +0 -0
- psychopy/app/Resources/light/filejs.png +0 -0
- psychopy/app/Resources/light/filejs@2x.png +0 -0
- psychopy/app/Resources/light/filejson.png +0 -0
- psychopy/app/Resources/light/filejson@2x.png +0 -0
- psychopy/app/Resources/light/filepkg.png +0 -0
- psychopy/app/Resources/light/filepkg@2x.png +0 -0
- psychopy/app/Resources/light/filepsyexp.png +0 -0
- psychopy/app/Resources/light/filepsyexp@2x.png +0 -0
- psychopy/app/Resources/light/filepy.png +0 -0
- psychopy/app/Resources/light/filepy@2x.png +0 -0
- psychopy/app/Resources/light/filetxt.png +0 -0
- psychopy/app/Resources/light/filetxt@2x.png +0 -0
- psychopy/app/Resources/light/fileunknown.png +0 -0
- psychopy/app/Resources/light/fileunknown@2x.png +0 -0
- psychopy/app/Resources/light/filevideo.png +0 -0
- psychopy/app/Resources/light/filevideo@2x.png +0 -0
- psychopy/app/Resources/light/find.png +0 -0
- psychopy/app/Resources/light/find@2x.png +0 -0
- psychopy/app/Resources/light/loop.png +0 -0
- psychopy/app/Resources/light/loop@2x.png +0 -0
- psychopy/app/Resources/light/regex.png +0 -0
- psychopy/app/Resources/light/regex@2x.png +0 -0
- psychopy/app/Resources/routine_templates/Basic.psyexp +0 -1
- psychopy/app/Resources/routine_templates/Misc.psyexp +0 -1
- psychopy/app/Resources/routine_templates/Online.psyexp +0 -2
- psychopy/app/Resources/routine_templates/Trials.psyexp +0 -1
- psychopy/app/Resources/splash.png +0 -0
- psychopy/app/Resources/splash@2x.png +0 -0
- psychopy/app/__init__.py +49 -8
- psychopy/app/__main__.py +3 -0
- psychopy/app/_psychopyApp.py +134 -125
- psychopy/app/builder/builder.py +42 -22
- psychopy/app/builder/dialogs/__init__.py +44 -11
- psychopy/app/builder/dialogs/dlgsCode.py +1 -1
- psychopy/app/builder/dialogs/dlgsConditions.py +1 -1
- psychopy/app/builder/dialogs/findDlg.py +106 -20
- psychopy/app/builder/dialogs/paramCtrls.py +42 -1
- psychopy/app/builder/validators.py +1 -1
- psychopy/app/coder/codeEditorBase.py +8 -8
- psychopy/app/coder/coder.py +32 -29
- psychopy/app/coder/fileBrowser.py +68 -22
- psychopy/app/coder/folding.py +1 -1
- psychopy/app/coder/psychoParser.py +1 -1
- psychopy/app/coder/repl.py +1 -1
- psychopy/app/coder/sourceTree.py +1 -1
- psychopy/app/connections/__init__.py +1 -1
- psychopy/app/connections/news.py +1 -1
- psychopy/app/connections/sendusage.py +1 -1
- psychopy/app/connections/updates.py +1 -1
- psychopy/app/console.py +1 -1
- psychopy/app/errorDlg.py +1 -1
- psychopy/app/frametracker.py +1 -1
- psychopy/app/idle.py +1 -1
- psychopy/app/jobs.py +5 -2
- psychopy/app/linuxconfig/__init__.py +1 -1
- psychopy/app/locale/ar_001/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/ar_001/LC_MESSAGE/messages.po +4 -4
- psychopy/app/locale/cs_CZ/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/da_DK/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/de_DE/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/de_DE/LC_MESSAGE/messages.po +3 -3
- psychopy/app/locale/el_GR/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/en_NZ/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/en_US/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/es_CO/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/es_CO/LC_MESSAGE/messages.po +4 -4
- psychopy/app/locale/es_ES/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/es_ES/LC_MESSAGE/messages.po +4 -4
- psychopy/app/locale/es_US/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/es_US/LC_MESSAGE/messages.po +4 -4
- psychopy/app/locale/et_EE/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/et_EE/LC_MESSAGE/messages.po +2 -2
- psychopy/app/locale/fa_IR/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/fa_IR/LC_MESSAGE/messages.po +1 -1
- psychopy/app/locale/fi_FI/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/fr_FR/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/fr_FR/LC_MESSAGE/messages.po +2 -2
- psychopy/app/locale/he_IL/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/he_IL/LC_MESSAGE/messages.po +2 -2
- psychopy/app/locale/hi_IN/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/hi_IN/LC_MESSAGE/messages.po +2 -2
- psychopy/app/locale/hu_HU/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/it_IT/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/it_IT/LC_MESSAGE/messages.po +2 -2
- psychopy/app/locale/ja_JP/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/ja_JP/LC_MESSAGE/messages.po +3421 -2396
- psychopy/app/locale/ko_KR/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/ms_MY/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/ms_MY/LC_MESSAGE/messages.po +2 -2
- psychopy/app/locale/nl_NL/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/nn_NO/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/pl_PL/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/pt_PT/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/pt_PT/LC_MESSAGE/messages.po +4 -4
- psychopy/app/locale/ro_RO/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/ru_RU/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/sv_SE/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/sv_SE/LC_MESSAGE/messages.po +2 -2
- psychopy/app/locale/tr_TR/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/tr_TR/LC_MESSAGE/messages.po +2 -2
- psychopy/app/locale/zh_CN/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/zh_CN/LC_MESSAGE/messages.po +3 -3
- psychopy/app/locale/zh_TW/LC_MESSAGE/messages.mo +0 -0
- psychopy/app/locale/zh_TW/LC_MESSAGE/messages.po +2 -2
- psychopy/app/{builder/localizedStrings.py → localizedStrings.py} +173 -26
- psychopy/app/pavlovia_ui/__init__.py +1 -1
- psychopy/app/pavlovia_ui/_base.py +1 -1
- psychopy/app/pavlovia_ui/functions.py +1 -1
- psychopy/app/pavlovia_ui/menu.py +1 -1
- psychopy/app/pavlovia_ui/project.py +1 -1
- psychopy/app/pavlovia_ui/search.py +1 -1
- psychopy/app/pavlovia_ui/sync.py +1 -1
- psychopy/app/pavlovia_ui/user.py +1 -1
- psychopy/app/plugin_manager/dialog.py +34 -96
- psychopy/app/plugin_manager/packages.py +10 -14
- psychopy/app/plugin_manager/plugins.py +64 -4
- psychopy/app/preferencesDlg.py +12 -37
- psychopy/app/psychopyApp.py +130 -44
- psychopy/app/ribbon.py +1 -0
- psychopy/app/runner/runner.py +19 -7
- psychopy/app/runner/scriptProcess.py +11 -6
- psychopy/app/stdout/stdOutRich.py +9 -2
- psychopy/app/themes/fonts.py +1 -1
- psychopy/app/themes/icons.py +2 -38
- psychopy/app/ui/__init__.py +1 -1
- psychopy/app/utils.py +3 -3
- psychopy/assets/default.mp3 +0 -0
- psychopy/assets/fonts/NotoSans-Bold.ttf +0 -0
- psychopy/assets/fonts/NotoSans-BoldItalic.ttf +0 -0
- psychopy/assets/fonts/NotoSans-Italic.ttf +0 -0
- psychopy/assets/fonts/NotoSans-Regular.ttf +0 -0
- psychopy/assets/voicekeyThresholdStim.wav +0 -0
- psychopy/clock.py +4 -1
- psychopy/colors.py +12 -5
- psychopy/core.py +1 -1
- psychopy/data/base.py +1 -1
- psychopy/data/experiment.py +151 -46
- psychopy/data/routine.py +27 -1
- psychopy/data/staircase.py +2 -1
- psychopy/data/trial.py +62 -14
- psychopy/data/utils.py +2 -2
- psychopy/demos/builder/Design Templates/branchedExperiment/branchedExperiment.psyexp +333 -218
- psychopy/demos/builder/Design Templates/psychophysicsStaircase/psychophysicsStaircase.psyexp +261 -239
- psychopy/demos/builder/Design Templates/psychophysicsStairsInterleaved/psychophysicsStaircaseInterleaved.psyexp +319 -180
- psychopy/demos/builder/Design Templates/randomisedBlocks/randomisedBlocks.psyexp +204 -116
- psychopy/demos/builder/Experiments/BART/assets/background.jpg +0 -0
- psychopy/demos/builder/Experiments/BART/assets/blueBalloon.png +0 -0
- psychopy/demos/builder/Experiments/BART/assets/greenBalloon.png +0 -0
- psychopy/demos/builder/Experiments/BART/assets/redBalloon.png +0 -0
- psychopy/demos/builder/Experiments/BART/bart.psyexp +779 -866
- psychopy/demos/builder/Experiments/BigFiveInventory/BFI.psyexp +242 -180
- psychopy/demos/builder/Experiments/GoNoGo/gng.psyexp +419 -406
- psychopy/demos/builder/Experiments/dragAndDrop/README.md +2 -37
- psychopy/demos/builder/Experiments/dragAndDrop/drag_and_drop.psyexp +460 -1204
- psychopy/demos/builder/Experiments/dragAndDrop/stimuli/blank_grid.png +0 -0
- psychopy/demos/builder/Experiments/dragAndDrop/stimuli/make_shapes.psyexp +221 -0
- psychopy/demos/builder/Experiments/dragAndDrop/stimuli/readme.md +4 -0
- psychopy/demos/builder/Experiments/dragAndDrop/stimuli/solution_1.png +0 -0
- psychopy/demos/builder/Experiments/dragAndDrop/stimuli/solution_10.png +0 -0
- psychopy/demos/builder/Experiments/dragAndDrop/stimuli/solution_2.png +0 -0
- psychopy/demos/builder/Experiments/dragAndDrop/stimuli/solution_3.png +0 -0
- psychopy/demos/builder/Experiments/dragAndDrop/stimuli/solution_4.png +0 -0
- psychopy/demos/builder/Experiments/dragAndDrop/stimuli/solution_5.png +0 -0
- psychopy/demos/builder/Experiments/dragAndDrop/stimuli/solution_6.png +0 -0
- psychopy/demos/builder/Experiments/dragAndDrop/stimuli/solution_7.png +0 -0
- psychopy/demos/builder/Experiments/dragAndDrop/stimuli/solution_8.png +0 -0
- psychopy/demos/builder/Experiments/dragAndDrop/stimuli/solution_9.png +0 -0
- psychopy/demos/builder/Experiments/dragAndDrop/stimuli/solutions.xlsx +0 -0
- psychopy/demos/builder/Experiments/mentalRotation/MentalRotation.psyexp +583 -542
- psychopy/demos/builder/Experiments/navon/NavonTask.psyexp +458 -427
- psychopy/demos/builder/Experiments/sternberg/sternberg.psyexp +588 -550
- psychopy/demos/builder/Experiments/stroop/stroop.psyexp +303 -207
- psychopy/demos/builder/Experiments/stroopExtended/stroop.psyexp +390 -215
- psychopy/demos/builder/Experiments/stroopExtended/stroopReverse.psyexp +390 -215
- psychopy/demos/builder/Experiments/stroopVoice/stroopVoice.psyexp +357 -331
- psychopy/demos/builder/Feature Demos/buttonBox/buttonBoxDemo.psyexp +3 -2
- psychopy/demos/builder/Feature Demos/counterbalance/counterbalance.psyexp +287 -277
- psychopy/demos/builder/Feature Demos/gratings/gratings.psyexp +370 -320
- psychopy/demos/builder/Feature Demos/noise/noise.psyexp +452 -399
- psychopy/demos/builder/Feature Demos/panorama/panorama.psyexp +168 -133
- psychopy/demos/builder/Feature Demos/pilotMode/pilotMode.psyexp +4 -3
- psychopy/demos/builder/Feature Demos/progress/progressBar.psyexp +420 -392
- psychopy/demos/builder/Feature Demos/sliders/sliders.psyexp +917 -871
- psychopy/demos/builder/Feature Demos/visualValidator/readme.md +7 -0
- psychopy/demos/builder/Feature Demos/visualValidator/visualValidator.psyexp +200 -0
- psychopy/demos/builder/Hardware/EEG_parallel_component/EEG_triggers_parallel_comp.psyexp +25 -9
- psychopy/demos/builder/Hardware/EEG_serial_code/EEG_triggers_serial_code.psyexp +372 -361
- psychopy/demos/builder/Hardware/EEG_serial_component/EEG_triggers_serial_comp.psyexp +25 -9
- psychopy/demos/builder/Hardware/EGI_netstation/stroop.psyexp +320 -235
- psychopy/demos/builder/Hardware/Eyetracking_visual_search/visualSearch.psyexp +790 -651
- psychopy/demos/builder/Hardware/camera/camera.psyexp +326 -246
- psychopy/demos/builder/Hardware/eyetracking/eyetracking.psyexp +432 -327
- psychopy/demos/builder/Hardware/eyetracking_custom_cal/eyetracking_custom_cal.psyexp +440 -321
- psychopy/demos/builder/Hardware/fMRI/fMRI_demo.psyexp +190 -181
- psychopy/demos/builder/Hardware/lab_streaming_layer/lsl_triggers_demo.psyexp +323 -312
- psychopy/demos/builder/Hardware/lab_streaming_layer/lsl_triggers_demo_legacy.psyexp +360 -0
- psychopy/demos/builder/Hardware/lab_streaming_layer/lsl_triggers_demo_legacy_legacy.psyexp +312 -0
- psychopy/demos/builder/Hardware/lab_streaming_layer_legacy/lsl_triggers_demo_legacy.psyexp +329 -273
- psychopy/demos/builder/Hardware/lab_streaming_layer_legacy/lsl_triggers_demo_legacy_legacy.psyexp +360 -0
- psychopy/demos/builder/Hardware/lab_streaming_layer_legacy/lsl_triggers_demo_legacy_legacy_legacy.psyexp +312 -0
- psychopy/demos/builder/Hardware/microphone/microphone.psyexp +450 -404
- psychopy/demos/builder/Hardware/pump/pump.psyexp +593 -329
- psychopy/demos/builder/Helper Tools/achorVSalignment/FlowCircular-Regular.ttf +0 -0
- psychopy/demos/builder/Helper Tools/achorVSalignment/anchorAlignment.psyexp +336 -274
- psychopy/demos/builder/Helper Tools/clockFace/clockFace.psyexp +200 -149
- psychopy/demos/builder/Helper Tools/colors/colors.psyexp +300 -279
- psychopy/demos/builder/Helper Tools/drawPolygon/drawPolygon.psyexp +677 -564
- psychopy/demos/builder/Helper Tools/keyNameFinder/keyNameFinder.psyexp +214 -158
- psychopy/demos/builder/Helper Tools/spatialUnits/unitDemo.psyexp +195 -146
- psychopy/demos/coder/experiment control/runtimeInfo.py +1 -1
- psychopy/devices/__init__.py +1 -1
- psychopy/event.py +1 -1
- psychopy/exceptions.py +1 -1
- psychopy/experiment/__init__.py +1 -1
- psychopy/experiment/_experiment.py +30 -9
- psychopy/experiment/components/__init__.py +1 -6
- psychopy/experiment/components/_base.py +44 -19
- psychopy/experiment/components/aperture/__init__.py +1 -1
- psychopy/experiment/components/brush/__init__.py +2 -2
- psychopy/experiment/components/button/__init__.py +24 -28
- psychopy/experiment/components/camera/__init__.py +38 -39
- psychopy/experiment/components/code/__init__.py +1 -1
- psychopy/experiment/components/dots/__init__.py +1 -1
- psychopy/experiment/components/eyetracker_record/__init__.py +7 -3
- psychopy/experiment/components/form/__init__.py +3 -3
- psychopy/experiment/components/grating/__init__.py +1 -1
- psychopy/experiment/components/image/__init__.py +1 -1
- psychopy/experiment/components/joyButtons/__init__.py +2 -2
- psychopy/experiment/components/joyButtons/virtualJoyButtons.py +1 -1
- psychopy/experiment/components/joystick/__init__.py +3 -3
- psychopy/experiment/components/joystick/virtualJoystick.py +1 -1
- psychopy/experiment/components/keyboard/__init__.py +98 -122
- psychopy/experiment/components/microphone/__init__.py +54 -98
- psychopy/experiment/components/mouse/__init__.py +92 -93
- psychopy/experiment/components/movie/__init__.py +28 -50
- psychopy/experiment/components/parallelOut/__init__.py +3 -3
- psychopy/experiment/components/polygon/__init__.py +2 -3
- psychopy/experiment/components/roi/__init__.py +2 -2
- psychopy/experiment/components/routineSettings/__init__.py +2 -0
- psychopy/experiment/components/serialOut/__init__.py +7 -7
- psychopy/experiment/components/settings/__init__.py +317 -313
- psychopy/experiment/components/settings/eyetracking.py +108 -0
- psychopy/experiment/components/slider/__init__.py +5 -5
- psychopy/experiment/components/sound/__init__.py +168 -78
- psychopy/experiment/components/soundsensor/__init__.py +361 -0
- psychopy/experiment/components/soundsensor/classic/soundsensor.png +0 -0
- psychopy/experiment/components/soundsensor/classic/soundsensor@2x.png +0 -0
- psychopy/experiment/components/soundsensor/dark/soundsensor.png +0 -0
- psychopy/experiment/components/soundsensor/dark/soundsensor@2x.png +0 -0
- psychopy/experiment/components/soundsensor/light/soundsensor.png +0 -0
- psychopy/experiment/components/soundsensor/light/soundsensor@2x.png +0 -0
- psychopy/experiment/components/static/__init__.py +59 -33
- psychopy/experiment/components/text/__init__.py +2 -6
- psychopy/experiment/components/textbox/__init__.py +3 -7
- psychopy/experiment/components/unknown/__init__.py +2 -0
- psychopy/experiment/components/unknownPlugin/__init__.py +2 -0
- psychopy/experiment/exports.py +1 -1
- psychopy/experiment/flow.py +2 -2
- psychopy/experiment/localization.py +1 -1
- psychopy/experiment/loops.py +43 -10
- psychopy/experiment/params.py +6 -4
- psychopy/experiment/plugins.py +8 -1
- psychopy/experiment/py2js.py +1 -1
- psychopy/experiment/py2js_transpiler.py +1 -1
- psychopy/experiment/routines/__init__.py +1 -1
- psychopy/experiment/routines/_base.py +23 -24
- psychopy/experiment/routines/audioValidator/__init__.py +343 -0
- psychopy/experiment/routines/audioValidator/classic/audio_validator.png +0 -0
- psychopy/experiment/routines/audioValidator/classic/audio_validator@2x.png +0 -0
- psychopy/experiment/routines/audioValidator/dark/audio_validator.png +0 -0
- psychopy/experiment/routines/audioValidator/dark/audio_validator@2x.png +0 -0
- psychopy/experiment/routines/audioValidator/light/audio_validator.png +0 -0
- psychopy/experiment/routines/audioValidator/light/audio_validator@2x.png +0 -0
- psychopy/experiment/routines/eyetracker_calibrate/__init__.py +76 -17
- psychopy/experiment/routines/eyetracker_validate/__init__.py +1 -1
- psychopy/experiment/routines/unknown/__init__.py +2 -0
- psychopy/experiment/routines/{photodiodeValidator → visualValidator}/__init__.py +89 -120
- psychopy/experiment/routines/visualValidator/classic/visual_validator.png +0 -0
- psychopy/experiment/routines/visualValidator/classic/visual_validator@2x.png +0 -0
- psychopy/experiment/routines/visualValidator/dark/visual_validator.png +0 -0
- psychopy/experiment/routines/visualValidator/dark/visual_validator@2x.png +0 -0
- psychopy/experiment/routines/visualValidator/light/visual_validator.png +0 -0
- psychopy/experiment/routines/visualValidator/light/visual_validator@2x.png +0 -0
- psychopy/experiment/utils.py +1 -1
- psychopy/gui/__init__.py +1 -1
- psychopy/gui/qtgui.py +15 -6
- psychopy/gui/wxgui.py +1 -1
- psychopy/hardware/__init__.py +0 -1
- psychopy/hardware/base.py +147 -16
- psychopy/hardware/bbtk/__init__.py +10 -16
- psychopy/hardware/brainproducts.py +7 -13
- psychopy/hardware/button.py +21 -2
- psychopy/hardware/buttonbox/__init__.py +1 -1
- psychopy/hardware/camera/__init__.py +18 -5
- psychopy/hardware/cedrus.py +5 -16
- psychopy/hardware/crs/__init__.py +1 -1
- psychopy/hardware/crs/bits.py +36 -33
- psychopy/hardware/crs/colorcal.py +8 -11
- psychopy/hardware/crs/optical.py +7 -10
- psychopy/hardware/crs/shaders.py +18 -5
- psychopy/hardware/emotiv.py +1 -1
- psychopy/hardware/emulator.py +11 -5
- psychopy/hardware/exceptions.py +86 -0
- psychopy/hardware/forp.py +18 -23
- psychopy/hardware/gammasci.py +8 -3
- psychopy/hardware/iolab.py +8 -19
- psychopy/hardware/joystick/__init__.py +865 -266
- psychopy/hardware/joystick/_base.py +251 -0
- psychopy/hardware/joystick/backend_glfw.py +306 -0
- psychopy/hardware/joystick/backend_pyglet.py +309 -0
- psychopy/hardware/joystick/mappings.py +287 -0
- psychopy/hardware/keyboard.py +4 -2
- psychopy/hardware/labhackers.py +1 -1
- psychopy/hardware/labjacks.py +9 -13
- psychopy/hardware/{photodiode.py → lightsensor.py} +146 -203
- psychopy/hardware/listener.py +9 -8
- psychopy/hardware/manager.py +24 -35
- psychopy/hardware/microphone.py +535 -155
- psychopy/hardware/minolta.py +14 -4
- psychopy/hardware/mouse/__init__.py +1 -1
- psychopy/hardware/photometer/__init__.py +2 -2
- psychopy/hardware/pr.py +14 -4
- psychopy/hardware/qmix.py +18 -27
- psychopy/hardware/serialdevice.py +43 -12
- psychopy/hardware/soundsensor.py +473 -0
- psychopy/hardware/spatial/__init__.py +231 -0
- psychopy/hardware/speaker.py +298 -36
- psychopy/hardware/triggerbox/__init__.py +1 -1
- psychopy/hardware/triggerbox/base.py +1 -1
- psychopy/hardware/triggerbox/parallel.py +1 -1
- psychopy/info.py +1 -1
- psychopy/iohub/devices/eyetracker/__init__.py +10 -18
- psychopy/iohub/devices/eyetracker/calibration/procedure.py +15 -33
- psychopy/iohub/devices/eyetracker/hw/gazepoint/__init__.py +2 -2
- psychopy/iohub/devices/eyetracker/hw/gazepoint/gp3/__init__.py +1 -0
- psychopy/iohub/devices/eyetracker/hw/gazepoint/gp3/eyetracker.py +10 -0
- psychopy/iohub/devices/eyetracker/hw/pupil_labs/neon/__init__.py +1 -0
- psychopy/iohub/devices/mouse/linux2.py +2 -1
- psychopy/layout.py +1 -1
- psychopy/liaison.py +91 -39
- psychopy/locale_setup.py +11 -1
- psychopy/localization/__init__.py +1 -1
- psychopy/localization/_localization.py +1 -1
- psychopy/localization/messages.pot +2 -2
- psychopy/logging.py +14 -12
- psychopy/microphone.py +4 -3
- psychopy/misc.py +1 -1
- psychopy/monitors/MonitorCenter.py +3 -3
- psychopy/monitors/__init__.py +1 -1
- psychopy/monitors/calibData.py +1 -1
- psychopy/monitors/calibTools.py +3 -2
- psychopy/platform_specific/__init__.py +1 -1
- psychopy/platform_specific/darwin.py +1 -1
- psychopy/platform_specific/linux.py +1 -1
- psychopy/platform_specific/win32.py +1 -1
- psychopy/plugins/__init__.py +26 -17
- psychopy/plugins/util.py +65 -0
- psychopy/preferences/Darwin.spec +11 -3
- psychopy/preferences/FreeBSD.spec +11 -3
- psychopy/preferences/Linux.spec +11 -3
- psychopy/preferences/Windows.spec +11 -3
- psychopy/preferences/__init__.py +1 -1
- psychopy/preferences/baseNoArch.spec +11 -3
- psychopy/preferences/hints.py +78 -61
- psychopy/preferences/preferences.py +82 -13
- psychopy/projects/__init__.py +1 -1
- psychopy/projects/pavlovia.py +29 -13
- psychopy/scripts/psyexpCompile.py +1 -1
- psychopy/session.py +81 -8
- psychopy/sound/__init__.py +25 -10
- psychopy/sound/_base.py +134 -34
- psychopy/sound/audioclip.py +38 -15
- psychopy/sound/audiodevice.py +1 -1
- psychopy/sound/backend_ptb.py +53 -321
- psychopy/sound/backend_pygame.py +7 -3
- psychopy/sound/backend_pyo.py +53 -22
- psychopy/sound/backend_pysound.py +10 -27
- psychopy/sound/backend_sounddevice.py +33 -21
- psychopy/sound/exceptions.py +1 -1
- psychopy/sound/microphone.py +83 -5
- psychopy/sound/transcribe.py +3 -3
- psychopy/tests/data/test_basic_run.py +1 -0
- psychopy/tests/data/test_sounds/default_16000.wav +0 -0
- psychopy/tests/data/test_sounds/default_192000.wav +0 -0
- psychopy/tests/data/test_sounds/default_22050.wav +0 -0
- psychopy/tests/data/test_sounds/default_32000.wav +0 -0
- psychopy/tests/data/test_sounds/default_44100.wav +0 -0
- psychopy/tests/data/test_sounds/default_48000.wav +0 -0
- psychopy/tests/data/test_sounds/default_8000.wav +0 -0
- psychopy/tests/data/test_sounds/default_96000.wav +0 -0
- psychopy/tests/test_alerts/test_alerttools.py +2 -1
- psychopy/tests/test_app/test_command_line.py +65 -0
- psychopy/tests/test_data/test_TrialHandler2.py +18 -7
- psychopy/tests/test_demos/test_builder_demos.py +1 -1
- psychopy/tests/test_experiment/needs_wx/componsTemplate.txt +5238 -4188
- psychopy/tests/test_experiment/needs_wx/test_components.py +1 -1
- psychopy/tests/test_experiment/test_components/test_RoutineSettingsComponent.py +16 -0
- psychopy/tests/test_experiment/test_components/test_all_components.py +1 -1
- psychopy/tests/test_experiment/test_components/test_base_components.py +26 -17
- psychopy/tests/test_experiment/test_loops.py +12 -4
- psychopy/tests/test_experiment/test_params.py +17 -4
- psychopy/tests/test_experiment/test_routines/test_PhotodiodeValidationRoutine.py +2 -2
- psychopy/tests/test_hardware/test_photodiode.py +66 -0
- psychopy/tests/test_liaison/test_Liaison.py +4 -4
- psychopy/tests/test_misc/test_clock.py +2 -0
- psychopy/tests/test_misc/test_color.py +2 -0
- psychopy/tests/test_misc/test_event.py +1 -0
- psychopy/tests/test_plugins/__init__.py +0 -0
- psychopy/tests/test_plugins/test_plugin_stubs.py +125 -0
- psychopy/tests/test_sound/test_sound.py +111 -40
- psychopy/tests/test_tools/test_colorspacetools.py +24 -23
- psychopy/tests/test_tools/test_mathtools.py +9 -9
- psychopy/tests/test_tools/test_viewtools.py +101 -0
- psychopy/tests/test_validators/__init__.py +0 -0
- psychopy/tests/test_validators/test_voicekeyValidator.py +95 -0
- psychopy/tests/test_visual/test_all_stimuli.py +2 -2
- psychopy/tests/test_visual/test_basevisual.py +37 -7
- psychopy/tests/test_visual/test_button.py +2 -2
- psychopy/tests/test_visual/test_circle.py +10 -2
- psychopy/tests/test_visual/test_dots.py +1 -1
- psychopy/tests/test_visual/test_form.py +13 -13
- psychopy/tests/test_visual/test_gamma.py +3 -3
- psychopy/tests/test_visual/test_image.py +2 -2
- psychopy/tests/test_visual/test_progress.py +2 -2
- psychopy/tests/test_visual/test_roi.py +8 -2
- psychopy/tests/test_visual/test_shape.py +2 -2
- psychopy/tests/test_visual/test_slider.py +2 -2
- psychopy/tests/test_visual/test_target.py +2 -2
- psychopy/tests/test_visual/test_textbox.py +6 -8
- psychopy/tests/test_visual/test_winScalePos.py +6 -5
- psychopy/tests/test_visual/test_window.py +17 -0
- psychopy/tests/utils.py +51 -1
- psychopy/tools/__init__.py +1 -1
- psychopy/tools/arraytools.py +2 -2
- psychopy/tools/attributetools.py +52 -1
- psychopy/tools/audiotools.py +4 -1
- psychopy/tools/colorspacetools.py +6 -4
- psychopy/tools/coordinatetools.py +1 -1
- psychopy/tools/fileerrortools.py +21 -9
- psychopy/tools/filetools.py +2 -2
- psychopy/tools/fontmanager.py +47 -28
- psychopy/tools/gltools.py +2967 -559
- psychopy/tools/imagetools.py +1 -1
- psychopy/tools/mathtools.py +997 -127
- psychopy/tools/monitorunittools.py +7 -1
- psychopy/tools/movietools.py +1 -2
- psychopy/tools/pkgtools.py +157 -127
- psychopy/tools/plottools.py +1 -1
- psychopy/tools/rifttools.py +1 -1
- psychopy/tools/stereotools.py +1 -1
- psychopy/tools/stimulustools.py +172 -2
- psychopy/tools/stringtools.py +22 -2
- psychopy/tools/systemtools.py +1 -1
- psychopy/tools/typetools.py +1 -1
- psychopy/tools/unittools.py +1 -1
- psychopy/tools/versionchooser.py +3 -1
- psychopy/tools/viewtools.py +54 -70
- psychopy/tools/wizard.py +2 -2
- psychopy/validation/__init__.py +6 -0
- psychopy/validation/audio.py +74 -0
- psychopy/validation/visual.py +115 -0
- psychopy/visual/__init__.py +1 -4
- psychopy/visual/aperture.py +9 -6
- psychopy/visual/backends/__init__.py +1 -1
- psychopy/visual/backends/_base.py +1 -1
- psychopy/visual/backends/gamma.py +1 -1
- psychopy/visual/backends/glfwbackend.py +8 -12
- psychopy/visual/backends/pygamebackend.py +1 -1
- psychopy/visual/backends/pygletbackend.py +32 -11
- psychopy/visual/basevisual.py +93 -13
- psychopy/visual/brush.py +1 -1
- psychopy/visual/bufferimage.py +90 -10
- psychopy/visual/button.py +1 -1
- psychopy/visual/circle.py +12 -20
- psychopy/visual/custommouse.py +1 -1
- psychopy/visual/dot.py +80 -14
- psychopy/visual/elementarray.py +84 -10
- psychopy/visual/filters.py +1 -1
- psychopy/visual/form.py +43 -28
- psychopy/visual/grating.py +105 -25
- psychopy/visual/helpers.py +4 -2
- psychopy/visual/image.py +98 -20
- psychopy/visual/line.py +15 -25
- psychopy/visual/movie.py +1 -1
- psychopy/visual/movie2.py +4 -3
- psychopy/visual/movie3.py +4 -3
- psychopy/visual/movies/__init__.py +1 -1
- psychopy/visual/movies/frame.py +1 -1
- psychopy/visual/movies/metadata.py +1 -1
- psychopy/visual/movies/players/__init__.py +1 -1
- psychopy/visual/movies/players/_base.py +1 -1
- psychopy/visual/movies/players/ffpyplayer_player.py +2 -3
- psychopy/visual/nnlvs.py +9 -6
- psychopy/visual/noise.py +4 -16
- psychopy/visual/patch.py +4 -3
- psychopy/visual/pie.py +3 -14
- psychopy/visual/polygon.py +21 -28
- psychopy/visual/radial.py +4 -18
- psychopy/visual/ratingscale.py +4 -3
- psychopy/visual/rect.py +16 -25
- psychopy/visual/rift.py +8 -2
- psychopy/visual/secondorder.py +4 -16
- psychopy/visual/shaders.py +620 -286
- psychopy/visual/shape.py +281 -90
- psychopy/visual/simpleimage.py +1 -1
- psychopy/visual/slider.py +78 -25
- psychopy/visual/stim3d.py +5 -608
- psychopy/visual/text.py +13 -3
- psychopy/visual/textbox2/textbox2.py +188 -56
- psychopy/visual/vlcmoviestim.py +1 -1
- psychopy/visual/window.py +374 -201
- psychopy/web.py +1 -1
- {psychopy-2024.2.5.dist-info → psychopy-2025.1.1.dist-info}/METADATA +13 -12
- {psychopy-2024.2.5.dist-info → psychopy-2025.1.1.dist-info}/RECORD +647 -624
- {psychopy-2024.2.5.dist-info → psychopy-2025.1.1.dist-info}/WHEEL +1 -1
- psychopy/.DS_Store +0 -0
- psychopy/__init__.py.orig +0 -65
- psychopy/app/.DS_Store +0 -0
- psychopy/app/Resources/.DS_Store +0 -0
- psychopy/app/Resources/classic/filecsv16.png +0 -0
- psychopy/app/Resources/classic/fileimage16.png +0 -0
- psychopy/app/Resources/classic/fileunknown16.png +0 -0
- psychopy/app/Resources/dark/filecsv16.png +0 -0
- psychopy/app/Resources/dark/filecsv16@2x.png +0 -0
- psychopy/app/Resources/dark/fileimage16.png +0 -0
- psychopy/app/Resources/dark/fileimage16@2x.png +0 -0
- psychopy/app/Resources/dark/fileunknown16.png +0 -0
- psychopy/app/Resources/dark/fileunknown16@2x.png +0 -0
- psychopy/app/Resources/fonts/OpenSans-Bold.ttf +0 -0
- psychopy/app/Resources/fonts/OpenSans-BoldItalic.ttf +0 -0
- psychopy/app/Resources/fonts/OpenSans-ExtraBold.ttf +0 -0
- psychopy/app/Resources/fonts/OpenSans-ExtraBoldItalic.ttf +0 -0
- psychopy/app/Resources/fonts/OpenSans-Italic.ttf +0 -0
- psychopy/app/Resources/fonts/OpenSans-Light.ttf +0 -0
- psychopy/app/Resources/fonts/OpenSans-LightItalic.ttf +0 -0
- psychopy/app/Resources/fonts/OpenSans-Regular.ttf +0 -0
- psychopy/app/Resources/fonts/OpenSans-SemiBold.ttf +0 -0
- psychopy/app/Resources/fonts/OpenSans-SemiBoldItalic.ttf +0 -0
- psychopy/app/Resources/light/filecsv16.png +0 -0
- psychopy/app/Resources/light/filecsv16@2x.png +0 -0
- psychopy/app/Resources/light/fileimage16.png +0 -0
- psychopy/app/Resources/light/fileimage16@2x.png +0 -0
- psychopy/app/Resources/light/fileunknown16.png +0 -0
- psychopy/app/Resources/light/fileunknown16@2x.png +0 -0
- psychopy/app/Resources/psychopySplash.png +0 -0
- psychopy/app/Resources/psychopySplash@2x.png +0 -0
- psychopy/app/builder/builder.py.orig +0 -3932
- psychopy/app/builder/dialogs/__init__.py.orig +0 -1679
- psychopy/app/builder/dialogs/paramCtrls.py.orig +0 -713
- psychopy/app/colorpicker/__init__.py.orig +0 -411
- psychopy/app/locale/ar_001/.DS_Store +0 -0
- psychopy/app/locale/ar_001/LC_MESSAGE/.DS_Store +0 -0
- psychopy/core.py.orig +0 -169
- psychopy/demos/builder/.DS_Store +0 -0
- psychopy/demos/builder/Design Templates/randomisedBlocks/randomisedBlocks_lastrun.py +0 -330
- psychopy/demos/builder/Experiments/.DS_Store +0 -0
- psychopy/demos/builder/Experiments/dragAndDrop/archived_conditions.xlsx +0 -0
- psychopy/demos/builder/Experiments/dragAndDrop/draw grid stim.py +0 -61
- psychopy/demos/builder/Experiments/dragAndDrop/shapeMaker.psyexp +0 -91
- psychopy/demos/builder/Experiments/dragAndDrop/stimuli/grid_image_1.png +0 -0
- psychopy/demos/builder/Experiments/dragAndDrop/stimuli/grid_image_10.png +0 -0
- psychopy/demos/builder/Experiments/dragAndDrop/stimuli/grid_image_2.png +0 -0
- psychopy/demos/builder/Experiments/dragAndDrop/stimuli/grid_image_3.png +0 -0
- psychopy/demos/builder/Experiments/dragAndDrop/stimuli/grid_image_4.png +0 -0
- psychopy/demos/builder/Experiments/dragAndDrop/stimuli/grid_image_5.png +0 -0
- psychopy/demos/builder/Experiments/dragAndDrop/stimuli/grid_image_6.png +0 -0
- psychopy/demos/builder/Experiments/dragAndDrop/stimuli/grid_image_7.png +0 -0
- psychopy/demos/builder/Experiments/dragAndDrop/stimuli/grid_image_8.png +0 -0
- psychopy/demos/builder/Experiments/dragAndDrop/stimuli/grid_image_9.png +0 -0
- psychopy/demos/builder/Experiments/dragAndDrop/updated_conditions.xlsx +0 -0
- psychopy/demos/builder/Tools/.DS_Store +0 -0
- psychopy/demos/builder/Tools/gammaCalibration/.DS_Store +0 -0
- psychopy/demos/builder/Tools/gammaCalibration/data/.DS_Store +0 -0
- psychopy/demos/builder/Tools/gammaCalibration/data/_gamma_correction_visual_2022-05-18_14h18.29.439.csv +0 -38
- psychopy/demos/builder/Tools/gammaCalibration/data/_gamma_correction_visual_2022-05-18_14h18.29.439.log +0 -3418
- psychopy/demos/builder/Tools/gammaCalibration/data/_gamma_correction_visual_2022-05-18_14h18.29.439.psydat +0 -0
- psychopy/demos/builder/Tools/gammaCalibration/data/x1_gamma_correction_visual_2022-05-17_13h59.42.928.csv +0 -2
- psychopy/demos/builder/Tools/gammaCalibration/data/x1_gamma_correction_visual_2022-05-17_13h59.42.928.log +0 -15
- psychopy/demos/builder/Tools/gammaCalibration/data/x1_gamma_correction_visual_2022-05-17_13h59.42.928.psydat +0 -0
- psychopy/demos/builder/Tools/gammaCalibration/gamma_correction_visual_lastrun.py +0 -562
- psychopy/demos/coder/.DS_Store +0 -0
- psychopy/demos/coder/experiment control/info_gamma.pickle +0 -0
- psychopy/demos/coder/iohub/.iohpid +0 -1
- psychopy/demos/coder/iohub/eyetracking/.iohpid +0 -1
- psychopy/demos/coder/iohub/wintab/.DS_Store +0 -0
- psychopy/demos/coder/stimuli/.DS_Store +0 -0
- psychopy/experiment/_experiment.py.orig +0 -1032
- psychopy/experiment/components/.DS_Store +0 -0
- psychopy/experiment/components/_base.py.orig +0 -823
- psychopy/experiment/components/form/.DS_Store +0 -0
- psychopy/experiment/components/microphone/__init__.py.orig +0 -490
- psychopy/experiment/components/settings/__init__.py.orig +0 -1337
- psychopy/experiment/components/textbox/__init__.py.orig +0 -310
- psychopy/experiment/components/webcam/.DS_Store +0 -0
- psychopy/experiment/components/webcam/light/.DS_Store +0 -0
- psychopy/experiment/loops.py.orig +0 -829
- psychopy/experiment/params.py.orig +0 -408
- psychopy/experiment/routine.py.orig +0 -503
- psychopy/experiment/routines/photodiodeValidator/classic/photodiode_validator.png +0 -0
- psychopy/experiment/routines/photodiodeValidator/classic/photodiode_validator@2x.png +0 -0
- psychopy/experiment/routines/photodiodeValidator/dark/photodiode_validator.png +0 -0
- psychopy/experiment/routines/photodiodeValidator/dark/photodiode_validator@2x.png +0 -0
- psychopy/experiment/routines/photodiodeValidator/light/photodiode_validator.png +0 -0
- psychopy/experiment/routines/photodiodeValidator/light/photodiode_validator@2x.png +0 -0
- psychopy/hardware/.DS_Store +0 -0
- psychopy/hardware/brainproducts.py.orig +0 -680
- psychopy/hardware/iolab.py.orig +0 -238
- psychopy/iohub/datastore/__init__.py.orig +0 -443
- psychopy/iohub/datastore/util.py.orig +0 -692
- psychopy/iohub/devices/mouse/darwin.py.orig +0 -427
- psychopy/iohub/devices/mouse/linux2.py.orig +0 -198
- psychopy/preferences/.DS_Store +0 -0
- psychopy/projects/pavlovia.py.orig +0 -1295
- psychopy/tests/.DS_Store +0 -0
- psychopy/tests/data/.DS_Store +0 -0
- psychopy/tests/data/TestCircle_fill_local.png +0 -0
- psychopy/tests/data/aperture1_normHexbackground_local.png +0 -0
- psychopy/tests/data/aperture1_norm_local.png +0 -0
- psychopy/tests/data/aperture2_normHexbackground_local.png +0 -0
- psychopy/tests/data/beatandrcos_height_local.png +0 -0
- psychopy/tests/data/beatandrcos_normAddBlend_local.png +0 -0
- psychopy/tests/data/beatandrcos_normHexbackground_local.png +0 -0
- psychopy/tests/data/beatandrcos_norm_local.png +0 -0
- psychopy/tests/data/beatandrcos_stencil_local.png +0 -0
- psychopy/tests/data/blend_add_height_local.png +0 -0
- psychopy/tests/data/blend_add_normAddBlend_local.png +0 -0
- psychopy/tests/data/blend_add_normHexbackground_local.png +0 -0
- psychopy/tests/data/blend_add_normNoShade_local.png +0 -0
- psychopy/tests/data/blend_add_norm_local.png +0 -0
- psychopy/tests/data/blend_add_stencil_local.png +0 -0
- psychopy/tests/data/bufferimg_gabor_height_local.png +0 -0
- psychopy/tests/data/bufferimg_gabor_normAddBlend_local.png +0 -0
- psychopy/tests/data/bufferimg_gabor_normHexbackground_local.png +0 -0
- psychopy/tests/data/bufferimg_gabor_normNoShade_local.png +0 -0
- psychopy/tests/data/bufferimg_gabor_norm_local.png +0 -0
- psychopy/tests/data/bufferimg_gabor_stencil_local.png +0 -0
- psychopy/tests/data/circleHex_height_local.png +0 -0
- psychopy/tests/data/circleHex_normAddBlend_local.png +0 -0
- psychopy/tests/data/circleHex_normHexbackground_local.png +0 -0
- psychopy/tests/data/circleHex_normNoShade_local.png +0 -0
- psychopy/tests/data/circleHex_norm_local.png +0 -0
- psychopy/tests/data/circleHex_stencil_local.png +0 -0
- psychopy/tests/data/color_comparison_local.png +0 -0
- psychopy/tests/data/correctScript/.DS_Store +0 -0
- psychopy/tests/data/dots_height_local.png +0 -0
- psychopy/tests/data/dots_normAddBlend_local.png +0 -0
- psychopy/tests/data/dots_normHexbackground_local.png +0 -0
- psychopy/tests/data/dots_normNoShade_local.png +0 -0
- psychopy/tests/data/dots_norm_local.png +0 -0
- psychopy/tests/data/dots_stencil_local.png +0 -0
- psychopy/tests/data/elarray1_height_local.png +0 -0
- psychopy/tests/data/elarray1_normAddBlend_local.png +0 -0
- psychopy/tests/data/elarray1_normHexbackground_local.png +0 -0
- psychopy/tests/data/elarray1_norm_local.png +0 -0
- psychopy/tests/data/elarray1_stencil_local.png +0 -0
- psychopy/tests/data/envelopeandrcos_height_local.png +0 -0
- psychopy/tests/data/envelopeandrcos_normAddBlend_local.png +0 -0
- psychopy/tests/data/envelopeandrcos_normHexbackground_local.png +0 -0
- psychopy/tests/data/envelopeandrcos_norm_local.png +0 -0
- psychopy/tests/data/envelopeandrcos_stencil_local.png +0 -0
- psychopy/tests/data/envelopepowerandrcos_height_local.png +0 -0
- psychopy/tests/data/envelopepowerandrcos_normAddBlend_local.png +0 -0
- psychopy/tests/data/envelopepowerandrcos_normHexbackground_local.png +0 -0
- psychopy/tests/data/envelopepowerandrcos_norm_local.png +0 -0
- psychopy/tests/data/envelopepowerandrcos_stencil_local.png +0 -0
- psychopy/tests/data/gabor1_height_local.png +0 -0
- psychopy/tests/data/gabor1_normAddBlend_local.png +0 -0
- psychopy/tests/data/gabor1_normHexbackground_local.png +0 -0
- psychopy/tests/data/gabor1_normNoShade_local.png +0 -0
- psychopy/tests/data/gabor1_norm_local.png +0 -0
- psychopy/tests/data/gabor1_stencil_local.png +0 -0
- psychopy/tests/data/greyscale_normHexbackground_local.png +0 -0
- psychopy/tests/data/imageAndGauss_height_local.png +0 -0
- psychopy/tests/data/imageAndGauss_normAddBlend_local.png +0 -0
- psychopy/tests/data/imageAndGauss_normHexbackground_local.png +0 -0
- psychopy/tests/data/imageAndGauss_normNoShade_local.png +0 -0
- psychopy/tests/data/imageAndGauss_norm_local.png +0 -0
- psychopy/tests/data/imageAndGauss_stencil_local.png +0 -0
- psychopy/tests/data/movFrame1_stencil_local.png +0 -0
- psychopy/tests/data/noiseAndRcos_height_local.png +0 -0
- psychopy/tests/data/noiseAndRcos_normAddBlend_local.png +0 -0
- psychopy/tests/data/noiseAndRcos_normHexbackground_local.png +0 -0
- psychopy/tests/data/noiseAndRcos_normNoShade_local.png +0 -0
- psychopy/tests/data/noiseAndRcos_norm_local.png +0 -0
- psychopy/tests/data/noiseAndRcos_stencil_local.png +0 -0
- psychopy/tests/data/noiseFiltersAndRcos_height_local.png +0 -0
- psychopy/tests/data/noiseFiltersAndRcos_normAddBlend_local.png +0 -0
- psychopy/tests/data/noiseFiltersAndRcos_normHexbackground_local.png +0 -0
- psychopy/tests/data/noiseFiltersAndRcos_normNoShade_local.png +0 -0
- psychopy/tests/data/noiseFiltersAndRcos_norm_local.png +0 -0
- psychopy/tests/data/noiseFiltersAndRcos_stencil_local.png +0 -0
- psychopy/tests/data/numpyImage_height_local.png +0 -0
- psychopy/tests/data/numpyImage_normAddBlend_local.png +0 -0
- psychopy/tests/data/numpyImage_normHexbackground_local.png +0 -0
- psychopy/tests/data/numpyImage_normNoShade_local.png +0 -0
- psychopy/tests/data/numpyImage_norm_local.png +0 -0
- psychopy/tests/data/numpyImage_stencil_local.png +0 -0
- psychopy/tests/data/shape2_1_normAddBlend_local.png +0 -0
- psychopy/tests/data/shape2_1_normHexbackground_local.png +0 -0
- psychopy/tests/data/shape2_1_normNoShade_local.png +0 -0
- psychopy/tests/data/shape2_1_norm_local.png +0 -0
- psychopy/tests/data/shape2_1_stencil_local.png +0 -0
- psychopy/tests/data/text1_height_local.png +0 -0
- psychopy/tests/data/text1_normAddBlend_local.png +0 -0
- psychopy/tests/data/text1_normHexbackground_local.png +0 -0
- psychopy/tests/data/text1_norm_local.png +0 -0
- psychopy/tests/data/text1_stencil_local.png +0 -0
- psychopy/tests/data/wedge1_height_local.png +0 -0
- psychopy/tests/data/wedge1_normAddBlend_local.png +0 -0
- psychopy/tests/data/wedge1_normHexbackground_local.png +0 -0
- psychopy/tests/data/wedge1_normNoShade_local.png +0 -0
- psychopy/tests/data/wedge1_norm_local.png +0 -0
- psychopy/tests/data/wedge1_stencil_local.png +0 -0
- psychopy/tests/test_app/.DS_Store +0 -0
- psychopy/tests/test_app/test_builder/.DS_Store +0 -0
- psychopy/tests/test_app/test_builder/data/_2021_ 5_03_1206.log +0 -177
- psychopy/tests/test_app/test_builder/data/_2021_ 5_03_1206.psydat +0 -0
- psychopy/tests/test_app/test_builder/data/_2021_ 5_03_1206.xlsx +0 -0
- psychopy/tests/test_app/test_builder/data/_2021_ 5_03_1324.log +0 -168
- psychopy/tests/test_app/test_builder/data/_2021_ 5_03_1324.psydat +0 -0
- psychopy/tests/test_app/test_builder/data/_2021_ 5_03_1324.xlsx +0 -0
- psychopy/tests/test_data/.DS_Store +0 -0
- psychopy/tests/test_hardware/test_CRS_BitsSharp.py +0 -67
- psychopy/tests/test_hardware/test_CRS_BitsSharp.py.orig +0 -68
- psychopy/tests/test_hardware/test_CRS_bitsShaders.py +0 -110
- psychopy/tests/test_visual/test_image.py.orig +0 -219
- psychopy/visual/basevisual.py.orig +0 -1723
- psychopy/visual/form.py.orig +0 -1181
- psychopy/visual/text.py.orig +0 -752
- psychopy/visual/textbox2/textbox2.py.orig +0 -1315
- psychopy/visual/windowwarp.py.orig +0 -463
- /psychopy/{app/cortex.log → alerts/alertsCatalogue/3600.yaml} +0 -0
- /psychopy/{app/Resources → assets}/fonts/Arvo-Bold.ttf +0 -0
- /psychopy/{app/Resources → assets}/fonts/Arvo-BoldItalic.ttf +0 -0
- /psychopy/{app/Resources → assets}/fonts/Arvo-Italic.ttf +0 -0
- /psychopy/{app/Resources → assets}/fonts/Arvo-Regular.ttf +0 -0
- /psychopy/{app/Resources → assets}/fonts/DejaVuSerif.ttf +0 -0
- /psychopy/{app/Resources → assets}/fonts/IndieFlower-Regular.ttf +0 -0
- /psychopy/{app/Resources → assets}/fonts/JetBrainsMono-Italic-VariableFont_wght.ttf +0 -0
- /psychopy/{app/Resources → assets}/fonts/JetBrainsMono-VariableFont_wght.ttf +0 -0
- /psychopy/demos/builder/Experiments/{GoNoGo → goNoGo}/readme.md +0 -0
- {psychopy-2024.2.5.dist-info → psychopy-2025.1.1.dist-info}/entry_points.txt +0 -0
- {psychopy-2024.2.5.dist-info → psychopy-2025.1.1.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,324 +1,802 @@
|
|
|
1
1
|
#!/usr/bin/env python
|
|
2
2
|
# -*- coding: utf-8 -*-
|
|
3
3
|
|
|
4
|
+
# Part of the PsychoPy library
|
|
5
|
+
# Copyright (C) 2002-2018 Jonathan Peirce (C) 2019-2025 Open Science Tools Ltd.
|
|
6
|
+
# Distributed under the terms of the GNU General Public License (GPL).
|
|
7
|
+
|
|
4
8
|
"""Control joysticks and gamepads from within PsychoPy.
|
|
5
9
|
|
|
6
|
-
|
|
7
|
-
updated.
|
|
10
|
+
For most backends, you do need a window using the same backend (and you need to
|
|
11
|
+
be flipping it) for the joystick to be updated.
|
|
12
|
+
|
|
13
|
+
"""
|
|
8
14
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
15
|
+
__all__ = [
|
|
16
|
+
'Joystick',
|
|
17
|
+
'JoystickError',
|
|
18
|
+
'JoystickAxisNotAvailableError',
|
|
19
|
+
'JoysticButtonNotAvailableError',
|
|
20
|
+
'getJoystickInterfaces']
|
|
12
21
|
|
|
13
|
-
|
|
14
|
-
|
|
22
|
+
from psychopy import logging, visual
|
|
23
|
+
from psychopy.hardware.joystick._base import BaseJoystickInterface
|
|
24
|
+
from psychopy.hardware.joystick.backend_pyglet import JoystickInterfacePyglet
|
|
25
|
+
from psychopy.hardware.joystick.backend_glfw import JoystickInterfaceGLFW
|
|
26
|
+
import psychopy.hardware.joystick.mappings as mappings
|
|
27
|
+
import psychopy.core as core
|
|
15
28
|
|
|
16
|
-
|
|
29
|
+
import math
|
|
30
|
+
import numpy as np
|
|
17
31
|
|
|
18
|
-
|
|
19
|
-
|
|
32
|
+
# backend to use when creating joystick objects
|
|
33
|
+
backend = 'pyglet' # 'pyglet' or 'pygame'
|
|
20
34
|
|
|
21
|
-
|
|
22
|
-
|
|
35
|
+
# constants
|
|
36
|
+
JOYSTICK_AXIS_X = JOYSTICK_BUTTON_A = 0
|
|
37
|
+
JOYSTICK_AXIS_Y = JOYSTICK_BUTTON_B = 1
|
|
38
|
+
JOYSTICK_AXIS_Z = JOYSTICK_BUTTON_X = 2
|
|
39
|
+
JOYSTICK_AXIS_RX = JOYSTICK_BUTTON_Y = 3
|
|
40
|
+
JOYSTICK_AXIS_RY = 4
|
|
41
|
+
JOYSTICK_AXIS_RZ = 5
|
|
23
42
|
|
|
24
|
-
nJoys = joystick.getNumJoysticks() # to check if we have any
|
|
25
|
-
id = 0
|
|
26
|
-
joy = joystick.Joystick(id) # id must be <= nJoys - 1
|
|
27
43
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
win.flip() # flipping implicitly updates the joystick info
|
|
33
|
-
"""
|
|
44
|
+
class JoystickError(Exception):
|
|
45
|
+
"""Exception raised for errors in the joystick module.
|
|
46
|
+
"""
|
|
47
|
+
pass
|
|
34
48
|
|
|
35
|
-
try:
|
|
36
|
-
import pygame.joystick
|
|
37
|
-
havePygame = True
|
|
38
|
-
except Exception:
|
|
39
|
-
havePygame = False
|
|
40
|
-
|
|
41
|
-
try:
|
|
42
|
-
from pyglet import input as pyglet_input # pyglet 1.2+
|
|
43
|
-
from pyglet import app as pyglet_app
|
|
44
|
-
havePyglet = True
|
|
45
|
-
except Exception:
|
|
46
|
-
havePyglet = False
|
|
47
|
-
|
|
48
|
-
try:
|
|
49
|
-
import glfw
|
|
50
|
-
haveGLFW = True
|
|
51
|
-
except ImportError:
|
|
52
|
-
print("failed to import GLFW.")
|
|
53
|
-
haveGLFW = False
|
|
54
49
|
|
|
55
|
-
|
|
56
|
-
|
|
50
|
+
class JoystickBackendNotAvailableError(JoystickError):
|
|
51
|
+
"""Exception raised when the backend is not available.
|
|
52
|
+
"""
|
|
53
|
+
pass
|
|
57
54
|
|
|
58
55
|
|
|
59
|
-
|
|
60
|
-
"""
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
elif backend == 'glfw':
|
|
64
|
-
n_joys = 0
|
|
65
|
-
for joy in range(glfw.JOYSTICK_1, glfw.JOYSTICK_LAST):
|
|
66
|
-
if glfw.joystick_present(joy):
|
|
67
|
-
n_joys += 1
|
|
56
|
+
class JoystickAxisNotAvailableError(JoystickError):
|
|
57
|
+
"""Exception raised when an axis is not available on the joystick.
|
|
58
|
+
"""
|
|
59
|
+
pass
|
|
68
60
|
|
|
69
|
-
return n_joys
|
|
70
|
-
else:
|
|
71
|
-
pygame.joystick.init()
|
|
72
|
-
return pygame.joystick.get_count()
|
|
73
61
|
|
|
62
|
+
class InvalidInputNameError(JoystickError):
|
|
63
|
+
"""Exception raised when an input name is not valid.
|
|
64
|
+
"""
|
|
65
|
+
pass
|
|
74
66
|
|
|
75
|
-
if havePyglet:
|
|
76
|
-
class PygletDispatcher:
|
|
77
|
-
def dispatch_events(self):
|
|
78
|
-
pyglet_app.platform_event_loop.step(timeout=0.001)
|
|
79
67
|
|
|
80
|
-
|
|
68
|
+
class JoysticButtonNotAvailableError(JoystickError):
|
|
69
|
+
"""Exception raised when a button is not available on the joystick.
|
|
70
|
+
"""
|
|
71
|
+
pass
|
|
81
72
|
|
|
82
73
|
|
|
83
74
|
class Joystick:
|
|
75
|
+
"""Class for interfacing with a multi-axis joystick or gamepad.
|
|
76
|
+
|
|
77
|
+
Upon creating a `Joystick` object, the joystick device is opened and the
|
|
78
|
+
states of the device's axes and buttons can be read.
|
|
79
|
+
|
|
80
|
+
Values for the axes are returned as floating point numbers, typically
|
|
81
|
+
between -1.0 and +1.0 unless scaling is applied. The values for the buttons
|
|
82
|
+
are returned as booleans, where True indicates the button is pressed down
|
|
83
|
+
at the time the device was last polled.
|
|
84
|
+
|
|
85
|
+
Scaling factors can be set for each axis to adjust the range of the axis
|
|
86
|
+
values. The scaling factor is a floating point value that is multiplied by
|
|
87
|
+
the axis value. If the scaling factor is negative, the axis value is
|
|
88
|
+
inverted. Deadzones can also be applied for each axis to prevent small
|
|
89
|
+
fluctuations in the joystick's resting position from being interpreted as
|
|
90
|
+
valid input. The deadzone is a floating point value between 0.0 and 1.0. If
|
|
91
|
+
the absolute value of the axis value is less than the deadzone, the axis
|
|
92
|
+
value is set to zero.
|
|
93
|
+
|
|
94
|
+
Device inputs can be named to provide a more human-readable interface. The
|
|
95
|
+
names can be set for axes, buttons, and hats where they can be used to get
|
|
96
|
+
the input values instead of using the integer indices. Furthermore,
|
|
97
|
+
like inputs can be grouped together under a single name. For example, both
|
|
98
|
+
X and Y of a thumbstick can be grouped together under the name 'thumbstick'.
|
|
99
|
+
When getting the value of the thumbstick, a tuple of the X and Y values is
|
|
100
|
+
returned instead of having to get each axis individually.
|
|
101
|
+
|
|
102
|
+
Parameters
|
|
103
|
+
----------
|
|
104
|
+
device : int or str
|
|
105
|
+
The index or name of the joystick to control.
|
|
106
|
+
|
|
107
|
+
Examples
|
|
108
|
+
--------
|
|
109
|
+
Typical usage::
|
|
110
|
+
|
|
111
|
+
from psychopy.hardware import joystick
|
|
112
|
+
from psychopy import visual
|
|
113
|
+
|
|
114
|
+
joystick.backend='pyglet' # must match the Window
|
|
115
|
+
win = visual.Window([400,400], winType='pyglet')
|
|
116
|
+
|
|
117
|
+
nJoys = joystick.getNumJoysticks() # to check if we have any
|
|
118
|
+
id = 0
|
|
119
|
+
joy = joystick.Joystick(id) # id must be <= nJoys - 1
|
|
120
|
+
|
|
121
|
+
nAxes = joy.getNumAxes() # for interest
|
|
122
|
+
while True: # while presenting stimuli
|
|
123
|
+
joyX = joy.getX()
|
|
124
|
+
# ...
|
|
125
|
+
win.flip() # flipping implicitly updates the joystick info
|
|
126
|
+
|
|
127
|
+
Set the deadzone for axis 0 to 0.1::
|
|
128
|
+
|
|
129
|
+
joy.setAxisDeadzone(0, 0.1)
|
|
130
|
+
|
|
131
|
+
Set the scaling factor for 1 axis to 2.0::
|
|
132
|
+
|
|
133
|
+
joy.setAxisScale(1, 2.0)
|
|
134
|
+
|
|
135
|
+
Setting the names of the inputs can be useful for debugging and for
|
|
136
|
+
providing a more human-readable interface::
|
|
137
|
+
|
|
138
|
+
joy.setInputName('axis', 0, 'x')
|
|
139
|
+
joy.setInputName('axis', 1, 'y')
|
|
140
|
+
|
|
141
|
+
You can get the imput value by name by passing it to the get method for the
|
|
142
|
+
input type::
|
|
143
|
+
|
|
144
|
+
joy.getAxis('axis', 'x') # instead of joy.getAxis(0)
|
|
84
145
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
.. note:
|
|
89
|
-
|
|
90
|
-
You do need to be flipping frames (or dispatching events manually)
|
|
91
|
-
in order for the values of the joystick to be updated.
|
|
92
|
-
|
|
93
|
-
:Known issues:
|
|
94
|
-
|
|
95
|
-
Currently under pyglet backends the axis values initialise to zero
|
|
96
|
-
rather than reading the current true value. This gets fixed on the
|
|
97
|
-
first change to each axis.
|
|
98
|
-
"""
|
|
99
|
-
self.id = id
|
|
100
|
-
if backend == 'pyglet':
|
|
101
|
-
joys = pyglet_input.get_joysticks()
|
|
102
|
-
if id >= len(joys):
|
|
103
|
-
logging.error("You don't have that many joysticks attached "
|
|
104
|
-
"(remember that the first joystick has id=0 "
|
|
105
|
-
"etc...)")
|
|
106
|
-
else:
|
|
107
|
-
self._device = joys[id]
|
|
108
|
-
try:
|
|
109
|
-
self._device.open()
|
|
110
|
-
except pyglet_input.DeviceOpenException as e:
|
|
111
|
-
pass
|
|
112
|
-
self.name = self._device.device.name
|
|
113
|
-
if len(visual.openWindows) == 0:
|
|
114
|
-
logging.error(
|
|
115
|
-
"You need to open a window before creating your joystick")
|
|
116
|
-
else:
|
|
117
|
-
for win in visual.openWindows:
|
|
118
|
-
win()._eventDispatchers.append(pyglet_dispatcher)
|
|
119
|
-
elif backend == 'glfw':
|
|
120
|
-
# We can create a joystick anytime after glfwInit() is called, but
|
|
121
|
-
# there should be a window open first.
|
|
122
|
-
# Joystick events are processed when flipping the associated window.
|
|
123
|
-
if not glfw.init():
|
|
124
|
-
logging.error("GLFW could not be initialized. Exiting.")
|
|
125
|
-
|
|
126
|
-
# get all available joysticks, GLFW supports up to 16.
|
|
127
|
-
joys = []
|
|
128
|
-
for joy in range(glfw.JOYSTICK_1, glfw.JOYSTICK_LAST):
|
|
129
|
-
if glfw.joystick_present(joy):
|
|
130
|
-
joys.append(joy)
|
|
131
|
-
|
|
132
|
-
# error checks
|
|
133
|
-
if not joys: # if the list is empty, no joysticks were found
|
|
134
|
-
error_msg = ("No joysticks were found by the GLFW runtime. "
|
|
135
|
-
"Check connections and try again.")
|
|
136
|
-
logging.error(error_msg)
|
|
137
|
-
raise RuntimeError(error_msg)
|
|
138
|
-
elif id not in joys:
|
|
139
|
-
error_msg = ("You don't have that many joysticks attached "
|
|
140
|
-
"(remember that the first joystick has id=0 "
|
|
141
|
-
"etc...)")
|
|
142
|
-
logging.error(error_msg)
|
|
143
|
-
raise RuntimeError(error_msg)
|
|
144
|
-
|
|
145
|
-
self._device = id # just need the ID for GLFW
|
|
146
|
-
self.name = glfw.get_joystick_name(self._device).decode("utf-8")
|
|
147
|
-
|
|
148
|
-
if len(visual.openWindows) == 0:
|
|
149
|
-
logging.error(
|
|
150
|
-
"You need to open a window before creating your joystick")
|
|
151
|
-
else:
|
|
152
|
-
for win in visual.openWindows:
|
|
153
|
-
# sending the raw ID to the window.
|
|
154
|
-
win()._eventDispatchers.append(self._device)
|
|
146
|
+
Automatically set the input names to the default Xbox controller mapping
|
|
147
|
+
scheme::
|
|
155
148
|
|
|
149
|
+
joy.setInputScheme('xbox')
|
|
150
|
+
# ...
|
|
151
|
+
xVal, yVal = joy.getAxis('left_thumbstick')
|
|
152
|
+
leftTrigger, rightTrigger = joy.getAxis('triggers')
|
|
153
|
+
|
|
154
|
+
Notes
|
|
155
|
+
-----
|
|
156
|
+
* You do need to be flipping frames (or dispatching events manually) in
|
|
157
|
+
order for the values of the joystick to be updated.
|
|
158
|
+
* Currently under pyglet backends the axis values initialise to zero
|
|
159
|
+
rather than reading the current true value. This gets fixed on the first
|
|
160
|
+
change to each axis.
|
|
161
|
+
* Currently pygame (1.9.1) spits out lots of debug messages about the
|
|
162
|
+
joystick and these can't be turned off :-/
|
|
163
|
+
* The GLFW backend can be used without first opening a window and can be
|
|
164
|
+
used with other window backends.
|
|
165
|
+
|
|
166
|
+
"""
|
|
167
|
+
def __init__(self, device=0, **kwargs):
|
|
168
|
+
# get the joystick device interface
|
|
169
|
+
try:
|
|
170
|
+
joyInterface = getJoystickInterfaces()[backend]
|
|
171
|
+
logging.info(
|
|
172
|
+
"Using joystick interface '{}' for backend '{}'".format(
|
|
173
|
+
joyInterface.__name__, backend))
|
|
174
|
+
except KeyError:
|
|
175
|
+
logging.error(
|
|
176
|
+
"No joystick interface found for backend '{}'".format(
|
|
177
|
+
backend))
|
|
178
|
+
|
|
179
|
+
# create a device interface
|
|
180
|
+
self._joy = joyInterface(device, **kwargs)
|
|
181
|
+
|
|
182
|
+
# input counts for the device, these don't chnage after opening
|
|
183
|
+
self._numAxes = self._joy.getNumAxes()
|
|
184
|
+
self._numButtons = self._joy.getNumButtons()
|
|
185
|
+
self._numHats = self._joy.getNumHats()
|
|
186
|
+
|
|
187
|
+
# axis value modifiers
|
|
188
|
+
self._axisScale = [1.0] * self._numAxes
|
|
189
|
+
self._axisDeadzone = [0.0] * self._numAxes
|
|
190
|
+
|
|
191
|
+
# device states
|
|
192
|
+
self._lastUpdateTime = 0.0 # in experiment time
|
|
193
|
+
self._axisVals = np.zeros(self._numAxes, dtype=np.float32)
|
|
194
|
+
self._btnStates = np.zeros(self._numButtons, dtype=bool)
|
|
195
|
+
self._hatStates = np.zeros((self._numHats, 2), dtype=np.int8)
|
|
196
|
+
|
|
197
|
+
# VR and motion tracking properties
|
|
198
|
+
self._pos = np.zeros(3, dtype=np.float32)
|
|
199
|
+
self._ori = np.array([0., 0., 0., 1.], dtype=np.float32)
|
|
200
|
+
self._angularVel = np.zeros(3, dtype=np.float32)
|
|
201
|
+
self._linearVel = np.zeros(3, dtype=np.float32)
|
|
202
|
+
|
|
203
|
+
# axis name mapping, some defaults are provided for common axes
|
|
204
|
+
self._inputNames = {}
|
|
205
|
+
self.setInputScheme('default') # use default mapping scheme
|
|
206
|
+
|
|
207
|
+
def __del__(self):
|
|
208
|
+
"""Close the joystick device when the object is deleted.
|
|
209
|
+
"""
|
|
210
|
+
if hasattr(self, '_joy'):
|
|
211
|
+
self.close()
|
|
212
|
+
|
|
213
|
+
def lastUpdateTime(self):
|
|
214
|
+
"""Return the time of the last update to the joystick state.
|
|
215
|
+
|
|
216
|
+
Returns
|
|
217
|
+
-------
|
|
218
|
+
float
|
|
219
|
+
The time of the last update to the joystick state.
|
|
220
|
+
|
|
221
|
+
"""
|
|
222
|
+
return self._lastUpdateTime
|
|
223
|
+
|
|
224
|
+
def poll(self):
|
|
225
|
+
"""Poll the joystick device for the current state.
|
|
226
|
+
|
|
227
|
+
This method should be called at the beginning of each frame to update
|
|
228
|
+
the state of the joystick device. The time of the last update is stored
|
|
229
|
+
and can be accessed using the `lastUpdateTime` property.
|
|
230
|
+
|
|
231
|
+
"""
|
|
232
|
+
self._joy.update()
|
|
233
|
+
|
|
234
|
+
# update the internal state of the joystick
|
|
235
|
+
self._axisVals[:] = self.getAllAxes()
|
|
236
|
+
self._btnStates[:] = self.getAllButtons()
|
|
237
|
+
|
|
238
|
+
if backend != 'glfw': # cannot use hats with GLFW
|
|
239
|
+
self._hatStates[:] = self.getAllHats()
|
|
240
|
+
|
|
241
|
+
# update the VR properties
|
|
242
|
+
if self.hasTracking:
|
|
243
|
+
self._pos = self.getPos()
|
|
244
|
+
self._ori = self.getOri()
|
|
245
|
+
self._angularVel = self.getAngularVelocity()
|
|
246
|
+
self._linearVel = self.getLinearVelocity()
|
|
247
|
+
|
|
248
|
+
if self._joy.trackerData is None:
|
|
249
|
+
self._lastUpdateTime = core.getTime()
|
|
156
250
|
else:
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
251
|
+
self._lastUpdateTime = self._joy.trackerData._absSampleTime
|
|
252
|
+
|
|
253
|
+
return self._lastUpdateTime
|
|
254
|
+
|
|
255
|
+
@staticmethod
|
|
256
|
+
def getAvailableDevices():
|
|
257
|
+
"""Return a list of available joystick devices.
|
|
258
|
+
|
|
259
|
+
This method is used by `DeviceManager` to get a list of available
|
|
260
|
+
devices.
|
|
261
|
+
|
|
262
|
+
Returns
|
|
263
|
+
-------
|
|
264
|
+
list
|
|
265
|
+
A list of available joystick devices.
|
|
266
|
+
|
|
267
|
+
"""
|
|
268
|
+
# use the selected backend class to get the available devices
|
|
269
|
+
return getJoystickInterfaces()[backend].getAvailableDevices()
|
|
270
|
+
|
|
271
|
+
@property
|
|
272
|
+
def inputLib(self):
|
|
273
|
+
"""Input interface library used (`str`).
|
|
274
|
+
"""
|
|
275
|
+
if not hasattr(self, '_joy'):
|
|
276
|
+
return None
|
|
277
|
+
|
|
278
|
+
return self._joy.inputLib
|
|
279
|
+
|
|
280
|
+
@property
|
|
281
|
+
def hasTracking(self):
|
|
282
|
+
"""Check if the joystick has tracking capabilities.
|
|
283
|
+
|
|
284
|
+
Returns
|
|
285
|
+
-------
|
|
286
|
+
bool
|
|
287
|
+
True if the joystick has tracking capabilities, False otherwise.
|
|
288
|
+
|
|
289
|
+
"""
|
|
290
|
+
return self._joy.hasTracking
|
|
291
|
+
|
|
292
|
+
def isSameDevice(self, otherDevice):
|
|
293
|
+
"""Check if the device is the same as another device.
|
|
294
|
+
|
|
295
|
+
Parameters
|
|
296
|
+
----------
|
|
297
|
+
otherDevice : Joystick
|
|
298
|
+
The other device to compare against.
|
|
299
|
+
|
|
300
|
+
Returns
|
|
301
|
+
-------
|
|
302
|
+
bool
|
|
303
|
+
True if the devices are the same, False otherwise.
|
|
304
|
+
|
|
305
|
+
"""
|
|
306
|
+
# only need to check the index since the device ID is unique
|
|
307
|
+
return self._joy.isSameDevice(otherDevice._device)
|
|
308
|
+
|
|
309
|
+
def open(self):
|
|
310
|
+
"""Open the joystick device.
|
|
311
|
+
"""
|
|
312
|
+
if self.isOpen:
|
|
313
|
+
return
|
|
314
|
+
|
|
315
|
+
self._joy.open()
|
|
316
|
+
|
|
317
|
+
@property
|
|
318
|
+
def isOpen(self):
|
|
319
|
+
"""Check if the joystick device is open.
|
|
320
|
+
|
|
321
|
+
Returns
|
|
322
|
+
-------
|
|
323
|
+
bool
|
|
324
|
+
True if the joystick device is open, False otherwise.
|
|
325
|
+
|
|
326
|
+
"""
|
|
327
|
+
return self._joy.isOpen
|
|
328
|
+
|
|
329
|
+
def close(self):
|
|
330
|
+
"""Close the joystick device.
|
|
331
|
+
"""
|
|
332
|
+
if not self.isOpen:
|
|
333
|
+
return
|
|
334
|
+
|
|
335
|
+
self._joy.close()
|
|
336
|
+
|
|
337
|
+
@property
|
|
338
|
+
def name(self):
|
|
339
|
+
"""Name of the joystick reported by the system (`str`).
|
|
340
|
+
"""
|
|
341
|
+
return self.getName()
|
|
342
|
+
|
|
343
|
+
@property
|
|
344
|
+
def deviceIndex(self):
|
|
345
|
+
"""The index of the joystick (`int`).
|
|
346
|
+
"""
|
|
347
|
+
return self._deviceIndex
|
|
348
|
+
|
|
349
|
+
@property
|
|
350
|
+
def x(self):
|
|
351
|
+
"""The X axis value (`float`).
|
|
352
|
+
"""
|
|
353
|
+
return self.getX()
|
|
354
|
+
|
|
355
|
+
@property
|
|
356
|
+
def y(self):
|
|
357
|
+
"""The Y axis value (`float`).
|
|
358
|
+
"""
|
|
359
|
+
return self.getY()
|
|
360
|
+
|
|
361
|
+
@property
|
|
362
|
+
def z(self):
|
|
363
|
+
"""The Z axis value (`float`).
|
|
364
|
+
"""
|
|
365
|
+
return self.getZ()
|
|
366
|
+
|
|
367
|
+
@property
|
|
368
|
+
def rx(self):
|
|
369
|
+
"""The RX axis value (`float`).
|
|
370
|
+
"""
|
|
371
|
+
return self.getRX()
|
|
372
|
+
|
|
373
|
+
@property
|
|
374
|
+
def ry(self):
|
|
375
|
+
"""The RY axis value (`float`).
|
|
376
|
+
"""
|
|
377
|
+
return self.getRY()
|
|
378
|
+
|
|
379
|
+
@property
|
|
380
|
+
def rz(self):
|
|
381
|
+
"""The RZ axis value (`float`).
|
|
382
|
+
"""
|
|
383
|
+
return self.getRZ()
|
|
384
|
+
|
|
385
|
+
@property
|
|
386
|
+
def trackerData(self):
|
|
387
|
+
"""Tracker data for the controller.
|
|
388
|
+
|
|
389
|
+
Returns
|
|
390
|
+
-------
|
|
391
|
+
`TrackerData` or `None`
|
|
392
|
+
The tracker data.
|
|
393
|
+
|
|
394
|
+
"""
|
|
395
|
+
return self._joy.trackerData
|
|
161
396
|
|
|
162
397
|
def getName(self):
|
|
163
|
-
"""Return the manufacturer-defined name describing the device.
|
|
164
|
-
|
|
398
|
+
"""Return the manufacturer-defined name describing the device (`str`).
|
|
399
|
+
"""
|
|
400
|
+
return self._joy.getName()
|
|
165
401
|
|
|
166
|
-
def
|
|
167
|
-
"""
|
|
168
|
-
if backend == 'pyglet':
|
|
169
|
-
return len(self._device.buttons)
|
|
170
|
-
elif backend == 'glfw':
|
|
171
|
-
_, count = glfw.get_joystick_buttons(self._device)
|
|
172
|
-
return count
|
|
173
|
-
else:
|
|
174
|
-
return self._device.get_numbuttons()
|
|
402
|
+
def setInputScheme(self, mapping):
|
|
403
|
+
"""Set the input mapping scheme for the joystick.
|
|
175
404
|
|
|
176
|
-
|
|
177
|
-
|
|
405
|
+
The input mapping scheme determines the names of the inputs for the
|
|
406
|
+
joystick. The mapping scheme can be set to 'default', 'xbox', or
|
|
407
|
+
'custom'. The default mapping scheme provides names for the axes and
|
|
408
|
+
buttons that are common to most joysticks.
|
|
409
|
+
|
|
410
|
+
Note that setting the mapping scheme will overwrite any custom input
|
|
411
|
+
names that have been set prior to calling this method.
|
|
412
|
+
|
|
413
|
+
Parameters
|
|
414
|
+
----------
|
|
415
|
+
mapping : str
|
|
416
|
+
The mapping scheme to set. Must be one of 'default', 'xbox', or
|
|
417
|
+
'custom'.
|
|
178
418
|
|
|
179
|
-
buttonId should be a value from 0 to the number of buttons-1
|
|
180
419
|
"""
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
420
|
+
# get the mapping scheme
|
|
421
|
+
inputMap = mappings.getInputScheme(mapping, self.inputLib)
|
|
422
|
+
if inputMap is None:
|
|
423
|
+
raise ValueError("Invalid mapping scheme '{}'.".format(mapping))
|
|
424
|
+
|
|
425
|
+
logging.info(
|
|
426
|
+
"Setting input scheme for joystick to '{}'.".format(mapping))
|
|
427
|
+
|
|
428
|
+
# set the input names
|
|
429
|
+
self._inputNames = inputMap
|
|
430
|
+
|
|
431
|
+
def setInputName(self, inputType, inputIndex, name):
|
|
432
|
+
"""Set the name of an input.
|
|
433
|
+
|
|
434
|
+
Parameters
|
|
435
|
+
----------
|
|
436
|
+
inputType : str
|
|
437
|
+
The type of input to set the name for. Must be one of 'axis',
|
|
438
|
+
'button', or 'hat'.
|
|
439
|
+
inputIndex : int or list of int
|
|
440
|
+
The index of the input to set the name for. If a list of indices is
|
|
441
|
+
supplied, multiple axes will be grouped together.
|
|
442
|
+
name : str or None
|
|
443
|
+
The name to set for the axis. If None, the name for the axis is
|
|
444
|
+
removed.
|
|
445
|
+
|
|
446
|
+
Raises
|
|
447
|
+
------
|
|
448
|
+
ValueError
|
|
449
|
+
If the inputType is not 'axis', 'button', or 'hat'.
|
|
450
|
+
|
|
451
|
+
Examples
|
|
452
|
+
--------
|
|
453
|
+
Set the name of axis `0` to 'x' and get its value by name::
|
|
454
|
+
|
|
455
|
+
joy.setInputName('axis', 0, 'x')
|
|
456
|
+
xVal = joy.getAxis('x') # instead of joy.getAxis(0)
|
|
457
|
+
|
|
458
|
+
Joystick inputs often have multiple axes ganged together on a single
|
|
459
|
+
control, such as a thumbstick. You can group axes together by passing a
|
|
460
|
+
list of indices::
|
|
461
|
+
|
|
462
|
+
joy.setInputName('axis', [0, 1], 'left_thumbstick')
|
|
463
|
+
xVal, yVal = joy.getAxis('left_thumbstick') # returns 2 values
|
|
188
464
|
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
465
|
+
"""
|
|
466
|
+
if inputType not in ('axes', 'buttons', 'hats'):
|
|
467
|
+
raise ValueError("Input type must be 'axes', 'buttons', or 'hats'.")
|
|
468
|
+
|
|
469
|
+
if name is None:
|
|
470
|
+
if inputIndex in self._inputNames[inputType]:
|
|
471
|
+
del self._inputNames[inputType][inputIndex]
|
|
472
|
+
return
|
|
473
|
+
|
|
474
|
+
self._inputNames[inputType][inputIndex] = name
|
|
475
|
+
|
|
476
|
+
def _getIndexFromName(self, inputType, name):
|
|
477
|
+
"""Get the index of an input from its name.
|
|
478
|
+
|
|
479
|
+
Parameters
|
|
480
|
+
----------
|
|
481
|
+
inputType : str
|
|
482
|
+
The type of input to get the index for. Must be one of 'axis',
|
|
483
|
+
'button', or 'hat'.
|
|
484
|
+
name : str
|
|
485
|
+
The name of the input to get the index for.
|
|
486
|
+
|
|
487
|
+
Returns
|
|
488
|
+
-------
|
|
489
|
+
int or None
|
|
490
|
+
The index of the input. If the input name is not found, `None` is
|
|
491
|
+
returned.
|
|
492
|
+
|
|
493
|
+
Raises
|
|
494
|
+
------
|
|
495
|
+
InvalidInputNameError
|
|
496
|
+
If the input name is not valid or has not been set.
|
|
497
|
+
|
|
498
|
+
"""
|
|
499
|
+
inputIndex = self._inputNames[inputType].get(name, None)
|
|
500
|
+
if inputIndex is not None:
|
|
501
|
+
return inputIndex
|
|
201
502
|
|
|
202
|
-
|
|
203
|
-
"""Get the current values of all available hats as a list of tuples.
|
|
204
|
-
|
|
205
|
-
Each value is a tuple (x, y) where x and y can be -1, 0, +1
|
|
206
|
-
"""
|
|
207
|
-
hats = []
|
|
208
|
-
if backend == 'pyglet':
|
|
209
|
-
for ctrl in self._device.device.get_controls():
|
|
210
|
-
if ctrl.name != None and 'hat' in ctrl.name:
|
|
211
|
-
hats.append((self._device.hat_x, self._device.hat_y))
|
|
212
|
-
elif backend == 'glfw':
|
|
213
|
-
# GLFW treats hats as buttons
|
|
214
|
-
pass
|
|
215
|
-
else:
|
|
216
|
-
for n in range(self._device.get_numhats()):
|
|
217
|
-
hats.append(self._device.get_hat(n))
|
|
218
|
-
return hats
|
|
503
|
+
raise InvalidInputNameError("Input name '{}' is not valid.".format(name))
|
|
219
504
|
|
|
220
|
-
|
|
221
|
-
|
|
505
|
+
# --------------------------------------------------------------------------
|
|
506
|
+
# Axis filtering methods
|
|
507
|
+
#
|
|
222
508
|
|
|
223
|
-
|
|
224
|
-
|
|
509
|
+
def getAxisScale(self, axisId):
|
|
510
|
+
"""Get the scale factor for a given axis.
|
|
511
|
+
|
|
512
|
+
Parameters
|
|
513
|
+
----------
|
|
514
|
+
axisId : int
|
|
515
|
+
The axis ID to get the scale factor for.
|
|
516
|
+
|
|
517
|
+
Returns
|
|
518
|
+
-------
|
|
519
|
+
float
|
|
520
|
+
The scale factor for the given axis.
|
|
225
521
|
|
|
226
522
|
"""
|
|
227
|
-
|
|
228
|
-
return len(self.getAllHats())
|
|
229
|
-
elif backend == 'glfw':
|
|
230
|
-
return 0
|
|
231
|
-
else:
|
|
232
|
-
return self._device.get_numhats()
|
|
523
|
+
return self._axisScale[axisId]
|
|
233
524
|
|
|
234
|
-
def
|
|
235
|
-
"""
|
|
525
|
+
def setAxisScale(self, axisId, scale):
|
|
526
|
+
"""Set the scale factor for a given axis.
|
|
527
|
+
|
|
528
|
+
Parameters
|
|
529
|
+
----------
|
|
530
|
+
axisId : int or None
|
|
531
|
+
The axis ID to set the scale factor for. If None, set the scale
|
|
532
|
+
factor for all axes to the given value.
|
|
533
|
+
scale : float
|
|
534
|
+
The scale factor to set. This factor will be multiplied by the
|
|
535
|
+
axis value. If negative, the axis value will be inverted.
|
|
536
|
+
|
|
537
|
+
"""
|
|
538
|
+
if not isinstance(scale, (int, float)):
|
|
539
|
+
raise TypeError("Scaling factor must be a numeric type.")
|
|
540
|
+
|
|
541
|
+
if isinstance(axisId, str):
|
|
542
|
+
axisId = self._getIndexFromName('axes', axisId)
|
|
236
543
|
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
"""
|
|
240
|
-
if backend == 'pyglet':
|
|
241
|
-
if hatId == 0:
|
|
242
|
-
return self._device.hat
|
|
243
|
-
else:
|
|
244
|
-
return self.getAllHats()[hatId]
|
|
245
|
-
elif backend == 'glfw':
|
|
246
|
-
# does nothing, hats are buttons in GLFW
|
|
247
|
-
pass
|
|
544
|
+
if axisId is None:
|
|
545
|
+
self._axisScale = [scale] * len(self._axisScale)
|
|
248
546
|
else:
|
|
249
|
-
|
|
547
|
+
self._axisScale[axisId] = scale
|
|
548
|
+
|
|
549
|
+
def getAxisDeadzone(self, axisId):
|
|
550
|
+
"""Get the deadzone for a given axis.
|
|
551
|
+
|
|
552
|
+
Parameters
|
|
553
|
+
----------
|
|
554
|
+
axisId : int
|
|
555
|
+
The axis ID to get the deadzone for.
|
|
556
|
+
|
|
557
|
+
Returns
|
|
558
|
+
-------
|
|
559
|
+
float
|
|
560
|
+
The deadzone for the given axis.
|
|
561
|
+
|
|
562
|
+
"""
|
|
563
|
+
if axisId is None:
|
|
564
|
+
return self._axisDeadzone
|
|
565
|
+
|
|
566
|
+
if isinstance(axisId, str):
|
|
567
|
+
axisId = self._getIndexFromName('axes', axisId)
|
|
568
|
+
|
|
569
|
+
if isinstance(axisId, (list, tuple)):
|
|
570
|
+
return [self.getAxisDeadzone(ax) for ax in axisId]
|
|
571
|
+
|
|
572
|
+
return self._axisDeadzone[axisId]
|
|
573
|
+
|
|
574
|
+
def setAxisDeadzone(self, axisId=None, deadzone=0.1):
|
|
575
|
+
"""Set the deadzone for a given axis.
|
|
576
|
+
|
|
577
|
+
Parameters
|
|
578
|
+
----------
|
|
579
|
+
axisId : int, str, list or None
|
|
580
|
+
The axis ID to set the deadzone for. If None, set the deadzone for
|
|
581
|
+
all axes to the given value. A string can be supplied to set the
|
|
582
|
+
deadzone for an axis by name. A list of axes can also be supplied to
|
|
583
|
+
set the deadzone for multiple axes at once.
|
|
584
|
+
deadzone : float
|
|
585
|
+
The deadzone to set, must be between 0.0 and 1.0.
|
|
586
|
+
|
|
587
|
+
"""
|
|
588
|
+
if not isinstance(deadzone, (int, float)):
|
|
589
|
+
raise TypeError("Deadzone must be a numeric type.")
|
|
590
|
+
|
|
591
|
+
deadzone = min(1.0, max(0.0, deadzone))
|
|
592
|
+
if axisId is None:
|
|
593
|
+
self._axisDeadzone = [deadzone] * len(self._axisDeadzone)
|
|
594
|
+
return
|
|
595
|
+
|
|
596
|
+
if isinstance(axisId, str): # name supplied
|
|
597
|
+
axisId = self._getIndexFromName('axes', axisId)
|
|
598
|
+
|
|
599
|
+
if isinstance(axisId, (list, tuple)):
|
|
600
|
+
for ax in axisId:
|
|
601
|
+
self.setAxisDeadzone(ax, deadzone)
|
|
602
|
+
return
|
|
603
|
+
|
|
604
|
+
self._axisDeadzone[axisId] = deadzone
|
|
605
|
+
|
|
606
|
+
# --------------------------------------------------------------------------
|
|
607
|
+
# Axis methods
|
|
608
|
+
#
|
|
609
|
+
|
|
610
|
+
def getAllAxes(self):
|
|
611
|
+
"""Get a list of all current axis values (`int`).
|
|
612
|
+
"""
|
|
613
|
+
allAxes = self._joy.getAllAxes()
|
|
614
|
+
|
|
615
|
+
# apply scaling and deadzone to axes
|
|
616
|
+
for i, axisVal in enumerate(allAxes):
|
|
617
|
+
allAxes[i] = axisVal * self._axisScale[i] \
|
|
618
|
+
if abs(axisVal) >= self._axisDeadzone[i] else 0.0
|
|
619
|
+
|
|
620
|
+
return allAxes
|
|
621
|
+
|
|
622
|
+
def getNumAxes(self):
|
|
623
|
+
"""Get the number of available joystick axes.
|
|
624
|
+
|
|
625
|
+
The first axis usually corresponds to the X axis, the second to the Y
|
|
626
|
+
axis for most joysticks. Additional axes may be present for other
|
|
627
|
+
controls such as addtional thumbsticks or throttle lever.
|
|
628
|
+
|
|
629
|
+
Returns
|
|
630
|
+
-------
|
|
631
|
+
int
|
|
632
|
+
The number of axes found on the joystick.
|
|
633
|
+
|
|
634
|
+
"""
|
|
635
|
+
return self._numAxes
|
|
636
|
+
|
|
637
|
+
def getAxis(self, axisId):
|
|
638
|
+
"""Get the value of an axis by an integer id.
|
|
639
|
+
|
|
640
|
+
Parameters
|
|
641
|
+
----------
|
|
642
|
+
axisId : int, str or list
|
|
643
|
+
The axis ID to get the value for. If a string is supplied, the name
|
|
644
|
+
of the axis is used to get the value. If a list of axes indices or
|
|
645
|
+
names is supplied, a list of values is returned.
|
|
646
|
+
|
|
647
|
+
Returns
|
|
648
|
+
-------
|
|
649
|
+
float or list
|
|
650
|
+
The value of the axis. If a list of axes is supplied, a list of
|
|
651
|
+
values is returned.
|
|
652
|
+
|
|
653
|
+
"""
|
|
654
|
+
if isinstance(axisId, str): # name supplied
|
|
655
|
+
axisId = self._getIndexFromName('axes', axisId)
|
|
656
|
+
|
|
657
|
+
# is axisId a sequence?
|
|
658
|
+
if isinstance(axisId, (list, tuple)):
|
|
659
|
+
return [self.getAxis(ax) for ax in axisId] # recusively called
|
|
660
|
+
|
|
661
|
+
# get the axis value from `int` axisId
|
|
662
|
+
axisVal = self._joy.getAxis(axisId)
|
|
663
|
+
return axisVal * self._axisScale[axisId] \
|
|
664
|
+
if abs(axisVal) >= self._axisDeadzone[axisId] else 0.0
|
|
250
665
|
|
|
251
666
|
def getX(self):
|
|
252
667
|
"""Return the X axis value (equivalent to joystick.getAxis(0))."""
|
|
253
|
-
|
|
254
|
-
return self._device.x
|
|
255
|
-
elif backend == 'glfw':
|
|
256
|
-
return self.getAxis(0)
|
|
257
|
-
else:
|
|
258
|
-
return self._device.get_axis(0)
|
|
668
|
+
return self.getAxis(JOYSTICK_AXIS_X)
|
|
259
669
|
|
|
260
670
|
def getY(self):
|
|
261
671
|
"""Return the Y axis value (equivalent to joystick.getAxis(1))."""
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
672
|
+
return self.getAxis(JOYSTICK_AXIS_Y)
|
|
673
|
+
|
|
674
|
+
def getXY(self):
|
|
675
|
+
"""Return the X and Y axis values as a tuple.
|
|
676
|
+
|
|
677
|
+
Returns
|
|
678
|
+
-------
|
|
679
|
+
tuple
|
|
680
|
+
The X and Y axis values as a tuple.
|
|
681
|
+
|
|
682
|
+
"""
|
|
683
|
+
return self.getAxis([JOYSTICK_AXIS_X, JOYSTICK_AXIS_Y])
|
|
268
684
|
|
|
269
685
|
def getZ(self):
|
|
270
686
|
"""Return the Z axis value (equivalent to joystick.getAxis(2))."""
|
|
271
|
-
|
|
272
|
-
return self._device.z
|
|
273
|
-
elif backend == 'glfw':
|
|
274
|
-
return self.getAxis(2)
|
|
275
|
-
else:
|
|
276
|
-
return self._device.get_axis(2)
|
|
687
|
+
return self.getAxis(JOYSTICK_AXIS_Z)
|
|
277
688
|
|
|
278
|
-
def
|
|
279
|
-
"""
|
|
280
|
-
|
|
281
|
-
if backend == 'pyglet':
|
|
282
|
-
names = ['x', 'y', 'z', 'rx', 'ry', 'rz', ]
|
|
283
|
-
for axName in names:
|
|
284
|
-
if hasattr(self._device, axName):
|
|
285
|
-
axes.append(getattr(self._device, axName))
|
|
286
|
-
elif backend == 'glfw':
|
|
287
|
-
_axes, count = glfw.get_joystick_axes(self._device)
|
|
288
|
-
for i in range(count):
|
|
289
|
-
axes.append(_axes[i])
|
|
290
|
-
else:
|
|
291
|
-
for id in range(self._device.get_numaxes()):
|
|
292
|
-
axes.append(self._device.get_axis(id))
|
|
293
|
-
return axes
|
|
689
|
+
def getRX(self):
|
|
690
|
+
"""Return the RX axis value (equivalent to joystick.getAxis(3))."""
|
|
691
|
+
return self.getAxis(JOYSTICK_AXIS_RX)
|
|
294
692
|
|
|
295
|
-
def
|
|
296
|
-
"""Return the
|
|
693
|
+
def getRY(self):
|
|
694
|
+
"""Return the RY axis value (equivalent to joystick.getAxis(4))."""
|
|
695
|
+
return self.getAxis(JOYSTICK_AXIS_RY)
|
|
696
|
+
|
|
697
|
+
def getRZ(self):
|
|
698
|
+
"""Return the RZ axis value (equivalent to joystick.getAxis(5))."""
|
|
699
|
+
return self.getAxis(JOYSTICK_AXIS_RZ)
|
|
700
|
+
|
|
701
|
+
# --------------------------------------------------------------------------
|
|
702
|
+
# Button methods
|
|
703
|
+
#
|
|
704
|
+
|
|
705
|
+
def getNumButtons(self):
|
|
706
|
+
"""Get the number of buttons on the device (`int`).
|
|
707
|
+
|
|
708
|
+
Returns
|
|
709
|
+
-------
|
|
710
|
+
int
|
|
711
|
+
The number of buttons on the joystick.
|
|
297
712
|
|
|
298
713
|
"""
|
|
299
|
-
|
|
300
|
-
return len(self.getAllAxes())
|
|
301
|
-
elif backend == 'glfw':
|
|
302
|
-
_, count = glfw.get_joystick_axes(self._device)
|
|
303
|
-
return count
|
|
304
|
-
else:
|
|
305
|
-
return self._device.get_numaxes()
|
|
714
|
+
return self._numButtons
|
|
306
715
|
|
|
307
|
-
def
|
|
308
|
-
"""Get the
|
|
716
|
+
def getAllButtons(self):
|
|
717
|
+
"""Get the state of all buttons on the devics.
|
|
718
|
+
|
|
719
|
+
Returns
|
|
720
|
+
-------
|
|
721
|
+
list
|
|
722
|
+
A list of button states. Each state is a boolean.
|
|
309
723
|
|
|
310
|
-
(from 0 to number of axes - 1)
|
|
311
724
|
"""
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
725
|
+
return self._joy.getAllButtons()
|
|
726
|
+
|
|
727
|
+
def getButton(self, buttonId):
|
|
728
|
+
"""Get the state of a given button on the device (`bool`).
|
|
729
|
+
|
|
730
|
+
Parameters
|
|
731
|
+
----------
|
|
732
|
+
buttonId : int, str or list
|
|
733
|
+
The button ID to get the state for. If a string is supplied, the
|
|
734
|
+
name of the button is used to get the state. If a list of button
|
|
735
|
+
indices or names is supplied, a list of states is returned.
|
|
736
|
+
|
|
737
|
+
Returns
|
|
738
|
+
-------
|
|
739
|
+
bool or list
|
|
740
|
+
The state of the button. If a list of buttons was passed as
|
|
741
|
+
`buttonId`, a list of states is returned where each state is a
|
|
742
|
+
boolean.
|
|
743
|
+
|
|
744
|
+
"""
|
|
745
|
+
if isinstance(buttonId, str): # name supplied
|
|
746
|
+
buttonId = self._getIndexFromName('buttons', buttonId)
|
|
747
|
+
|
|
748
|
+
if isinstance(buttonId, (list, tuple)):
|
|
749
|
+
return [self.getButton(b) for b in buttonId]
|
|
750
|
+
|
|
751
|
+
return self._joy.getButton(buttonId)
|
|
752
|
+
|
|
753
|
+
# --------------------------------------------------------------------------
|
|
754
|
+
# Hat methods
|
|
755
|
+
#
|
|
756
|
+
def getNumHats(self):
|
|
757
|
+
"""Get the number of hats on this joystick.
|
|
758
|
+
|
|
759
|
+
The GLFW backend makes no distinction between hats and buttons. Calling
|
|
760
|
+
'getNumHats()' will return 0.
|
|
761
|
+
|
|
762
|
+
"""
|
|
763
|
+
return self._numHats
|
|
764
|
+
|
|
765
|
+
def getAllHats(self):
|
|
766
|
+
"""Get the current values of all available hats.
|
|
767
|
+
|
|
768
|
+
Returns
|
|
769
|
+
-------
|
|
770
|
+
list
|
|
771
|
+
Each value is a tuple (x, y) where x and y axis states are trinary
|
|
772
|
+
(-1, 0, +1)
|
|
773
|
+
|
|
774
|
+
"""
|
|
775
|
+
return self._joy.getAllHats()
|
|
776
|
+
|
|
777
|
+
def getHat(self, hatId=0):
|
|
778
|
+
"""Get the position of a particular hat.
|
|
779
|
+
|
|
780
|
+
Parameters
|
|
781
|
+
----------
|
|
782
|
+
hatId : int or str
|
|
783
|
+
The hat ID to get the position for. If a string is supplied, the
|
|
784
|
+
name of the hat is used to get the position.
|
|
785
|
+
|
|
786
|
+
Returns
|
|
787
|
+
-------
|
|
788
|
+
tuple
|
|
789
|
+
The position returned is an (x, y) tuple where x and y can be -1, 0
|
|
790
|
+
or +1.
|
|
791
|
+
|
|
792
|
+
"""
|
|
793
|
+
if isinstance(hatId, str): # name supplied
|
|
794
|
+
hatId = self._getIndexFromName('hats', hatId)
|
|
795
|
+
|
|
796
|
+
if isinstance(hatId, (list, tuple)):
|
|
797
|
+
return [self.getHat(h) for h in hatId]
|
|
798
|
+
|
|
799
|
+
return self._joy.getHat(hatId)
|
|
322
800
|
|
|
323
801
|
|
|
324
802
|
class XboxController(Joystick):
|
|
@@ -330,8 +808,9 @@ class XboxController(Joystick):
|
|
|
330
808
|
y_btn_state = xbctrl.y # get the state of the 'Y' button
|
|
331
809
|
|
|
332
810
|
"""
|
|
333
|
-
def __init__(self,
|
|
334
|
-
|
|
811
|
+
def __init__(self, deviceIndex, **kwargs):
|
|
812
|
+
deviceIndex = kwargs.get('id', deviceIndex) # legacy param
|
|
813
|
+
super(XboxController, self).__init__(deviceIndex)
|
|
335
814
|
|
|
336
815
|
# validate if this is an Xbox controller by its reported name
|
|
337
816
|
if self.name.find("Xbox 360") == -1:
|
|
@@ -595,3 +1074,123 @@ class XboxController(Joystick):
|
|
|
595
1074
|
val = 1.0
|
|
596
1075
|
|
|
597
1076
|
return val
|
|
1077
|
+
|
|
1078
|
+
|
|
1079
|
+
# Setter and getter methods for the joystick backend, this allows us to sanity
|
|
1080
|
+
# check the backend value before setting it.
|
|
1081
|
+
|
|
1082
|
+
def getBackend():
|
|
1083
|
+
"""Get the joystick backend in use.
|
|
1084
|
+
|
|
1085
|
+
Returns
|
|
1086
|
+
-------
|
|
1087
|
+
str
|
|
1088
|
+
The name of the joystick backend in use.
|
|
1089
|
+
|
|
1090
|
+
"""
|
|
1091
|
+
return backend
|
|
1092
|
+
|
|
1093
|
+
|
|
1094
|
+
def setBackend(inputLib):
|
|
1095
|
+
"""Set the joystick backend (input library) to use.
|
|
1096
|
+
|
|
1097
|
+
Successive instances of `Joystick` will use the backend set here. If the
|
|
1098
|
+
backend is not available, a `ValueError` is raised.
|
|
1099
|
+
|
|
1100
|
+
Parameters
|
|
1101
|
+
----------
|
|
1102
|
+
inputLib : str or None
|
|
1103
|
+
The name of the joystick input library to use. If None, the value will
|
|
1104
|
+
be set to match the window backend name. You cannot set the backend to
|
|
1105
|
+
None if there are no open windows.
|
|
1106
|
+
|
|
1107
|
+
Examples
|
|
1108
|
+
--------
|
|
1109
|
+
Set the joystick backend to 'glfw'::
|
|
1110
|
+
|
|
1111
|
+
joystick.setBackend('glfw')
|
|
1112
|
+
joy = joystick.Joystick(0) # uses the GLFW backend
|
|
1113
|
+
|
|
1114
|
+
joy.inputLib == 'glfw' # True
|
|
1115
|
+
|
|
1116
|
+
Use the window backend as the joystick backend::
|
|
1117
|
+
|
|
1118
|
+
win = visual.Window([400, 400], winType='pyglet') # create first!
|
|
1119
|
+
joystick.setBackend(None) # set to window backend
|
|
1120
|
+
print(joystick.getBackend()) # 'pyglet'
|
|
1121
|
+
|
|
1122
|
+
"""
|
|
1123
|
+
if inputLib is None:
|
|
1124
|
+
if not visual.openWindows:
|
|
1125
|
+
raise ValueError("Cannot determine the window backend.")
|
|
1126
|
+
|
|
1127
|
+
win = visual.openWindows[0]()
|
|
1128
|
+
inputLib = win.backend.winTypeName # get window backend name
|
|
1129
|
+
|
|
1130
|
+
# get available backends and check if the requested backend is available
|
|
1131
|
+
availableBackends = getJoystickInterfaces()
|
|
1132
|
+
if inputLib not in availableBackends.keys():
|
|
1133
|
+
raise JoystickBackendNotAvailableError(
|
|
1134
|
+
"Joystick backend '{}' is not available.".format(inputLib))
|
|
1135
|
+
|
|
1136
|
+
global backend # set the global backend
|
|
1137
|
+
backend = inputLib
|
|
1138
|
+
|
|
1139
|
+
|
|
1140
|
+
def getJoystickInterfaces():
|
|
1141
|
+
"""Get available joystick input interfaces.
|
|
1142
|
+
|
|
1143
|
+
Returns
|
|
1144
|
+
-------
|
|
1145
|
+
dict
|
|
1146
|
+
A mapping of joystick interfaces available where the key is the input
|
|
1147
|
+
library identifier and the value is the joystick interface class.
|
|
1148
|
+
Setting the backend to one of these keys will use the corresponding
|
|
1149
|
+
joystick interface.
|
|
1150
|
+
|
|
1151
|
+
"""
|
|
1152
|
+
foundJoystickInterfaces = {}
|
|
1153
|
+
|
|
1154
|
+
# look for subclasses of JoystickInterface in this module's namespace
|
|
1155
|
+
for name in globals():
|
|
1156
|
+
obj = globals()[name]
|
|
1157
|
+
if isinstance(obj, type) and issubclass(obj, BaseJoystickInterface):
|
|
1158
|
+
if obj != BaseJoystickInterface:
|
|
1159
|
+
foundJoystickInterfaces[obj._inputLib] = obj
|
|
1160
|
+
|
|
1161
|
+
return foundJoystickInterfaces.copy()
|
|
1162
|
+
|
|
1163
|
+
|
|
1164
|
+
def getAllJoysticks():
|
|
1165
|
+
"""Enumerate all available joysticks and return a dictionary of their
|
|
1166
|
+
information.
|
|
1167
|
+
|
|
1168
|
+
Uses the presently set joystick backend to get the available joysticks.
|
|
1169
|
+
|
|
1170
|
+
Returns
|
|
1171
|
+
-------
|
|
1172
|
+
list
|
|
1173
|
+
A list of dictionaries containing information about each available
|
|
1174
|
+
joystick. Information varies depending on the joystick interface used,
|
|
1175
|
+
however the `'index'` key is always present and contains the index of
|
|
1176
|
+
the joystick. Passing this index to the `Joystick` constructor will
|
|
1177
|
+
create a joystick object for that device.
|
|
1178
|
+
|
|
1179
|
+
Examples
|
|
1180
|
+
--------
|
|
1181
|
+
Get information about all available joysticks::
|
|
1182
|
+
|
|
1183
|
+
joysticks = getAllJoysticks()
|
|
1184
|
+
for joy in joysticks:
|
|
1185
|
+
print(joy)
|
|
1186
|
+
|
|
1187
|
+
Create a `Joystick` object for the first joystick found::
|
|
1188
|
+
|
|
1189
|
+
joy = Joystick(joysticks[0]['index'])
|
|
1190
|
+
|
|
1191
|
+
"""
|
|
1192
|
+
return Joystick.getAllJoysticks()
|
|
1193
|
+
|
|
1194
|
+
|
|
1195
|
+
if __name__ == "__main__":
|
|
1196
|
+
pass
|