pax_global_header00006660000000000000000000000064146745623450014532gustar00rootroot0000000000000052 comment=0f7286911fd03770088eeb571932b1ea51cf3f7a piper-0.8/000077500000000000000000000000001467456234500125205ustar00rootroot00000000000000piper-0.8/.github/000077500000000000000000000000001467456234500140605ustar00rootroot00000000000000piper-0.8/.github/ISSUE_TEMPLATE/000077500000000000000000000000001467456234500162435ustar00rootroot00000000000000piper-0.8/.github/ISSUE_TEMPLATE/bug_report.md000066400000000000000000000016471467456234500207450ustar00rootroot00000000000000--- name: Bug report about: Create a report to help us improve title: '' labels: bug assignees: '' --- **Information** - `ratbagd` version (`ratbagd --version`): - Piper version: - Distribution: - Device: - Kernel version (ex. `uname -srmo`): `KERNEL VERSION HERE` **Describe the bug** A clear and concise description of what the bug is. **To Reproduce** Please make sure your bug is reproducible with the CLI client, `ratbagctl`. If it is not open a bug report in libratbag instead. Steps to reproduce the behavior: 1. Go to '...' 2. Click on '....' 3. Scroll down to '....' 4. See error **Logs** Please start the daemon with verbosity and reproduce the issue. First make sure it isn't running already. ``` $ ratbagd --verbose=raw OUTPUT HERE ``` **Additional context** Add any other context about the problem here. piper-0.8/.github/ISSUE_TEMPLATE/feature_request.md000066400000000000000000000011341467456234500217670ustar00rootroot00000000000000--- name: Feature request about: Suggest an idea for this project title: '' labels: enhancement assignees: '' --- **Is your feature request related to a problem? Please describe.** A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] **Describe the solution you'd like** A clear and concise description of what you want to happen. **Describe alternatives you've considered** A clear and concise description of any alternative solutions or features you've considered. **Additional context** Add any other context or screenshots about the feature request here. piper-0.8/.github/workflows/000077500000000000000000000000001467456234500161155ustar00rootroot00000000000000piper-0.8/.github/workflows/codeql.yml000066400000000000000000000015061467456234500201110ustar00rootroot00000000000000name: "CodeQL" on: push: branches: [ "master" ] pull_request: branches: [ "master" ] schedule: - cron: "17 10 * * 5" jobs: analyze: name: Analyze runs-on: ubuntu-latest permissions: actions: read contents: read security-events: write strategy: fail-fast: false matrix: language: [ python ] steps: - name: Checkout uses: actions/checkout@v3 - name: Initialize CodeQL uses: github/codeql-action/init@v2 with: languages: ${{ matrix.language }} queries: +security-and-quality - name: Autobuild uses: github/codeql-action/autobuild@v2 - name: Perform CodeQL Analysis uses: github/codeql-action/analyze@v2 with: category: "/language:${{ matrix.language }}" piper-0.8/.github/workflows/main.yml000066400000000000000000000032511467456234500175650ustar00rootroot00000000000000name: linux on: [ push, pull_request ] env: UBUNTU_DEPS: | pkg-config gettext appstream python3 python-gi-dev python3-lxml python3-evdev gir1.2-rsvg-2.0 python3-gi-cairo flake8 gtk-update-icon-cache desktop-file-utils PIP_PACKAGES: meson ninja black ruff jobs: build-and-dist: runs-on: ubuntu-22.04 strategy: matrix: meson_args: - '-Druntime-dependency-checks=false' - '-Druntime-dependency-checks=false -Dbuildtype=plain' - '-Druntime-dependency-checks=false -Dbuildtype=release' steps: - uses: actions/checkout@v3 - uses: libratbag/libratbag/.github/actions/pkginstall@master with: apt: $UBUNTU_DEPS pip: $PIP_PACKAGES - name: meson install ${{matrix.meson_args}} uses: libratbag/libratbag/.github/actions/meson@master with: meson_args: --prefix=$PWD/_instdir ${{matrix.meson_args}} ninja_args: install - name: check installation of data files run: diff -u <(cd data/devices; ls *.device) <(cd _instdir/share/libratbag; ls *.device) - name: ninja uninstall uses: libratbag/libratbag/.github/actions/meson@master with: meson_args: --prefix=$PWD/_instdir ninja_args: uninstall - name: list any files left after uninstall run: (test -d _instdir && tree _instdir) || exit 0 # Capture all the meson logs, even if we failed - uses: actions/upload-artifact@v3 if: ${{ always() }} # even if we fail with: name: meson test logs path: | builddir/meson-logs/testlog*.txt builddir/meson-logs/meson-log.txt piper-0.8/COPYING000066400000000000000000000431331467456234500135570ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. piper-0.8/README.md000066400000000000000000000064431467456234500140060ustar00rootroot00000000000000Piper ===== Piper is a GTK+ application to configure gaming mice. Piper is merely a graphical frontend to the ratbagd DBus daemon, see [the libratbag README](https://github.com/libratbag/libratbag/blob/master/README.md#running-ratbagd-as-dbus-activated-systemd-service) for instructions on how to run ratbagd. If you are running piper from git, we recommend using libratbag from git as well to make sure the latest bugfixes are applied. Supported Devices ================= Piper is merely a frontend, the list of supported devices depends on libratbag. See [the libratbag device files](https://github.com/libratbag/libratbag/tree/master/data/devices) for a list of all known devices. The device-specific protocols usually have to be reverse-engineered and the features available may vary to the manufacturer's advertized features. Screenshots =========== ![resolution configuration screenshot](https://github.com/libratbag/piper/blob/wiki/screenshots/piper-resolutionpage.png) ![button configuration screenshot](https://github.com/libratbag/piper/blob/wiki/screenshots/piper-buttonpage.png) ![LED configuration screenshot](https://github.com/libratbag/piper/blob/wiki/screenshots/piper-ledpage.png) And if you see the mousetrap, something isn't right. Usually this means that either ratbagd is not running (like in this screenshot), ratbagd needs to be updated to a newer version, or some other unexpected error occured. ![The error page](https://github.com/libratbag/piper/blob/wiki/screenshots/piper-errorpage.png) Installing Piper ================ See [our Wiki](https://github.com/libratbag/piper/wiki/Installation) for how to install Piper. Building Piper from git ======================= Piper uses the [meson build system](http://mesonbuild.com/). Run the following commands to clone Piper and initialize the build: ```sh git clone https://github.com/libratbag/piper.git cd piper meson builddir --prefix=/usr/ ``` To build or re-build after code-changes and install, run: ```sh ninja -C builddir sudo ninja -C builddir install ``` Note: `builddir` is the build output directory and can be changed to any other directory name. See [our Wiki](https://github.com/libratbag/piper/wiki/Installation) for what to do when you encounter missing dependencies. Contributing ============ Yes please. It's best to contact us first to see what you could do. Note that the devices displayed by Piper come from libratbag. For quicker development iteration, there is a special binary `piper.devel` that uses data files from the git directory. This removes the need to install piper after every code change. ```sh ninja -C builddir ./builddir/piper.devel ``` Note that this still requires ratbagd to run on the system bus. Piper tries to conform to Python's PEP8 style guide using the `black` formatter. Checking if code is formatted is done as a part of the test suite. You can check if your code passes tests before submitting changes using the following command: ```sh meson test -C builddir ``` Source ====== ```sh git clone https://github.com/libratbag/piper.git ``` Bugs ==== Bugs can be reported in the issue tracker on our GitHub repo: https://github.com/libratbag/piper/issues License ======= Licensed under the GPLv2. See the [COPYING](https://github.com/libratbag/piper/blob/master/COPYING) file for the full license information. piper-0.8/data/000077500000000000000000000000001467456234500134315ustar00rootroot00000000000000piper-0.8/data/404.svg000066400000000000000000000255621467456234500144730ustar00rootroot00000000000000 image/svg+xml piper-0.8/data/enter-keyboard-shortcut.svg000066400000000000000000000433331467456234500207440ustar00rootroot00000000000000 image/svg+xml piper-0.8/data/generate-piper-gresource.xml.py000077500000000000000000000011141467456234500215050ustar00rootroot00000000000000#!/usr/bin/env python3 import sys from pathlib import Path infile = sys.argv[1] outfile = sys.argv[2] svgdir = sys.argv[3] print(f"Using input file: {infile}") print(f"Writing to output file: {outfile}") print(f"SVG directory: {svgdir}") with open(infile) as f_in, open(outfile, "w") as f_out: for line in f_in: if "@SVG_FILES@" in line: for svg in sorted(Path(svgdir).glob("*.svg")): f_out.write( line.replace("@SVG_FILES@", f"{svg.parent.name}/{svg.name}") ) continue f_out.write(line) piper-0.8/data/led-off.svg000066400000000000000000001324211467456234500154710ustar00rootroot00000000000000 image/svg+xml piper-0.8/data/meson.build000066400000000000000000000051251467456234500155760ustar00rootroot00000000000000gnome = import('gnome') desktopdir = join_paths(datadir, 'applications') icondir = join_paths(datadir, 'icons', 'hicolor', 'scalable', 'apps') symbolicicondir = join_paths(datadir, 'icons', 'hicolor', 'symbolic', 'apps') metainfodir = join_paths(datadir, 'metainfo') man1dir = join_paths(mandir, 'man1') conf = configuration_data() conf.set('version', meson.project_version()) conf.set('version_date', version_date) manpage = configure_file( input: files('piper.1.in'), output: 'piper.1', configuration: conf, ) install_man( manpage, install_dir: man1dir, ) about_dialog = configure_file(input: 'ui/AboutDialog.ui.in', output: 'AboutDialog.ui', configuration: conf) install_data('org.freedesktop.Piper.svg', install_dir: icondir) install_data('org.freedesktop.Piper-symbolic.svg', install_dir: symbolicicondir) i18n.merge_file(input: 'org.freedesktop.Piper.desktop.in', output: 'org.freedesktop.Piper.desktop', type: 'desktop', po_dir: podir, install: true, install_dir: desktopdir) appdata = configure_file(input: 'org.freedesktop.Piper.appdata.xml.in.in', output: 'org.freedesktop.Piper.appdata.xml.in', configuration: conf) appdata = i18n.merge_file(input: appdata, output: 'org.freedesktop.Piper.appdata.xml', type: 'xml', po_dir: podir, install: true, install_dir: metainfodir) appstreamcli = find_program('appstreamcli', required: false) if appstreamcli.found() test( 'validate appdata file', appstreamcli, args: ['validate', '--no-net', '--pedantic', appdata] ) endif svg_mapping = files('svgs/svg-lookup.ini') gresource = configure_file(input: 'piper.gresource.xml.in', output: 'piper.gresource.xml', command: ['generate-piper-gresource.xml.py', join_paths(meson.current_source_dir(), 'piper.gresource.xml.in'), join_paths(meson.current_build_dir(), 'piper.gresource.xml'), join_paths(meson.current_source_dir(), 'svgs')]) gnome.compile_resources('piper', gresource, source_dir: '.', dependencies: [about_dialog], gresource_bundle: true, install: true, install_dir: pkgdatadir) piper-0.8/data/org.freedesktop.Piper-symbolic.svg000066400000000000000000000151531467456234500221550ustar00rootroot00000000000000 piper-0.8/data/org.freedesktop.Piper.appdata.xml.in.in000066400000000000000000000036711467456234500227640ustar00rootroot00000000000000 org.freedesktop.Piper FSFAP GPL-2.0-or-later Piper Gaming mouse configuration utility

Piper is a graphical user interface to configure gaming mice. Configuration options include changing the resolution (DPI) of the mouse, adding and removing profiles, setting LED colors and changing button behaviors.

Piper requires libratbag’s ratbagd, the daemon to actually communicate with the mice. Piper is merely a front end to ratbagd, ratbagd must be installed and running when Piper is launched.

org.freedesktop.Piper.desktop The button configuraton page https://github.com/libratbag/piper/raw/wiki/screenshots/flathub/piper-buttonpage.png The LED configuraton page https://github.com/libratbag/piper/raw/wiki/screenshots/flathub/piper-ledpage.png The resolution configuraton page https://github.com/libratbag/piper/raw/wiki/screenshots/flathub/piper-resolutionpage.png https://github.com/libratbag/piper/ https://github.com/libratbag/piper/issues https://github.com/libratbag/piper/wiki piper piper
piper-0.8/data/org.freedesktop.Piper.desktop.in000066400000000000000000000007021467456234500216070ustar00rootroot00000000000000[Desktop Entry] Name=Piper Comment=Configurable mouse configuration utility Exec=piper # Translators: Do NOT translate or transliterate this text (this is an icon file name)! Icon=org.freedesktop.Piper Type=Application StartupNotify=true Categories=GTK;GNOME;Utility; # Translators: Search terms to find this application. Do NOT translate or localize the semicolons! The list MUST also end with a semicolon! Keywords=gaming;configuration;mouse;mice; piper-0.8/data/org.freedesktop.Piper.svg000066400000000000000000000156401467456234500203370ustar00rootroot00000000000000 piper-0.8/data/piper.1.in000066400000000000000000000004231467456234500152360ustar00rootroot00000000000000.TH PIPER 1 "@version_date@" "@version@" "User Commands" .SH NAME Piper \- GTK application to configure gaming devices .SH DESCRIPTION .SS "Usage:" .IP piper [OPTION] .SS "Help Options:" .TP \fB\-h\fR, \fB\-\-help\fR Show help options .SH "SEE ALSO" ratbagctl(1), ratbagd(8) piper-0.8/data/piper.gresource.xml.in000066400000000000000000000024021467456234500176720ustar00rootroot00000000000000 404.svg enter-keyboard-shortcut.svg led-off.svg svgs/svg-lookup.ini AboutDialog.ui ui/AdvancedPage.ui ui/ButtonDialog.ui ui/ButtonRow.ui ui/DeviceRow.ui ui/ErrorPerspective.ui ui/MousePerspective.ui ui/LedDialog.ui ui/OptionButton.ui ui/ProfileRow.ui ui/ResolutionRow.ui ui/ResolutionsPage.ui ui/WelcomePerspective.ui ui/Window.ui @SVG_FILES@ piper-0.8/data/svgs/000077500000000000000000000000001467456234500144135ustar00rootroot00000000000000piper-0.8/data/svgs/README.md000066400000000000000000000065731467456234500157050ustar00rootroot00000000000000libratbag gnome theme ==================== Requirements ------------ See the Logitech G403 for an example of a device with a small amount of buttons, and the Logitech G700 for an example of a device with a large amount of buttons. - Canvas size should be between 400x400 and 500x500 pixels. - Three layers in the final SVG: 1. a lower layer named "Device" with the device itself. Each button on the device should have an id `buttonX`, with `X` being the number of the button (so for button 0 the id would be `button0`). Similarly, each LED on the device should have an id `ledX`. 2. a middle layer named "Buttons" with the button leaders (see below for leaders). 3. an upper layer named "LEDs" with the LED leaders. - A leader line is a path that extends from the button or LED to the left or the right of the device (see below). Each leader line requires the following: - It should start with a 7x7 square placed on or close to the button or LED that it maps with. - From this square, a path should extend left or right (see below). - Each path should end with a 1x1 pixel with identifier `buttonX-leader` (or `ledX-leader`), where `X` is the number of the button (or LED) with which the leader maps. For button 0, this would be `button0-leader`. - All these elements should be grouped and given the identifier `buttonX-path` (or `ledX-path` for LEDs) - Leader lines should have a vertical spacing of at least 40 pixels. When there are several leader lines above and below each other, make the spacing between them equal. - If the device's scroll wheel supports horizontal tilting, add two small arrows left and right of the scroll wheel with the respective button identifiers (see the Logitech G700 for an example). Do not cut the scroll wheel in half vertically to map these buttons. - If there aren't too many buttons, preferably make the leaders point to the right with the device itself placed on the left. If the buttons would extend below or above the device, make some point to the left instead with the device itself centered in the middle. In this case, half of the leaders should extend to the left and the other half to the right. - When a leader points to the right, its 1x1 pixel should have a style property `text-align:start`. When a leader points to the left, its 1x1 pixel should have a style property `text-align:end`. - The canvas should be resized so that there is a 20px gap between the device and the edge of the canvas and no gap between the 1x1 pixels and the canvas. Please note that due to the way the SVG is drawn, you cannot rely on the z-ordering of elements to line up or cover elements (as noted in [this issue](https://github.com/libratbag/piper/issues/48), which includes links to examples). As such, please make sure that you align the elements appropriately; [this comment](https://github.com/libratbag/piper/issues/48#issuecomment-315979109) includes some helpful tips. Technique --------- The simplest approach is to find a photo of the device and import it into inkscape. Put it on the lowest layer, create a new layer "Device" above it and start tracing the outlines and edges of the device. Fill in the shapes and your device should resemble the underlying photo. Delete the photo layer, add leaders in their respective layers and you're done. Make sure the image looks ''toned-down'' and not realistic. Do not use dark or bright colors. piper-0.8/data/svgs/asus-generic-8btn-dpibot.svg000066400000000000000000000700451467456234500216570ustar00rootroot00000000000000 image/svg+xml piper-0.8/data/svgs/asus-generic-8btn.svg000066400000000000000000000651421467456234500204020ustar00rootroot00000000000000 image/svg+xml piper-0.8/data/svgs/asus-rog-chakram-x.svg000066400000000000000000001147721467456234500205610ustar00rootroot00000000000000 image/svg+xml piper-0.8/data/svgs/asus-rog-gladius2-origin-pink.svg000077700000000000000000000000001467456234500266022asus-generic-8btn.svgustar00rootroot00000000000000piper-0.8/data/svgs/asus-rog-gladius2-origin.svg000077700000000000000000000000001467456234500256432asus-generic-8btn.svgustar00rootroot00000000000000piper-0.8/data/svgs/asus-rog-harpe-wireless.svg000077700000000000000000000000001467456234500270552asus-generic-8btn-dpibot.svgustar00rootroot00000000000000piper-0.8/data/svgs/asus-rog-keris-wireless-aimpoint.svg000077700000000000000000000000001467456234500307112asus-generic-8btn-dpibot.svgustar00rootroot00000000000000piper-0.8/data/svgs/asus-rog-keris-wireless.svg000077700000000000000000000000001467456234500270732asus-generic-8btn-dpibot.svgustar00rootroot00000000000000piper-0.8/data/svgs/asus-rog-strix-carry.svg000077700000000000000000000000001467456234500251332asus-generic-8btn.svgustar00rootroot00000000000000piper-0.8/data/svgs/asus-rog-strix-impact2-wireless.svg000077700000000000000000000000001467456234500304642asus-generic-8btn-dpibot.svgustar00rootroot00000000000000piper-0.8/data/svgs/asus-rog-strix-impact2.svg000077700000000000000000000000001467456234500266312asus-generic-8btn-dpibot.svgustar00rootroot00000000000000piper-0.8/data/svgs/fallback.svg000066400000000000000000000762631467456234500167110ustar00rootroot00000000000000 image/svg+xml 404 piper-0.8/data/svgs/glorious-model-d.svg000066400000000000000000000412561467456234500203260ustar00rootroot00000000000000 image/svg+xml piper-0.8/data/svgs/glorious-model-o.svg000066400000000000000000000214551467456234500203400ustar00rootroot00000000000000 image/svg+xml piper-0.8/data/svgs/logitech-g-pro-keyboard.svg000066400000000000000000001550231467456234500215600ustar00rootroot00000000000000 image/svg+xml piper-0.8/data/svgs/logitech-g-pro-wireless.svg000066400000000000000000000614721467456234500216210ustar00rootroot00000000000000 image/svg+xml piper-0.8/data/svgs/logitech-g-pro-x-wireless-superlight.svg000066400000000000000000000377331467456234500242550ustar00rootroot00000000000000 image/svg+xml piper-0.8/data/svgs/logitech-g-pro.svg000066400000000000000000000545741467456234500177730ustar00rootroot00000000000000 image/svg+xml piper-0.8/data/svgs/logitech-g102-g203.svg000077700000000000000000000000001467456234500234062logitech-g-pro.svgustar00rootroot00000000000000piper-0.8/data/svgs/logitech-g300.svg000066400000000000000000000661121467456234500174070ustar00rootroot00000000000000 image/svg+xml piper-0.8/data/svgs/logitech-g303-se.svg000066400000000000000000000267241467456234500200240ustar00rootroot00000000000000 piper-0.8/data/svgs/logitech-g303.svg000066400000000000000000000547021467456234500174140ustar00rootroot00000000000000 image/svg+xml piper-0.8/data/svgs/logitech-g402.svg000066400000000000000000000705021467456234500174100ustar00rootroot00000000000000 image/svg+xml piper-0.8/data/svgs/logitech-g403.svg000066400000000000000000000517421467456234500174160ustar00rootroot00000000000000 image/svg+xml piper-0.8/data/svgs/logitech-g500.svg000066400000000000000000000514341467456234500174120ustar00rootroot00000000000000 image/svg+xml piper-0.8/data/svgs/logitech-g500s.svg000077700000000000000000000000001467456234500225512logitech-g500.svgustar00rootroot00000000000000piper-0.8/data/svgs/logitech-g502-x.svg000066400000000000000000000730771467456234500176700ustar00rootroot00000000000000 image/svg+xml piper-0.8/data/svgs/logitech-g502.svg000066400000000000000000001030111467456234500174010ustar00rootroot00000000000000 image/svg+xml piper-0.8/data/svgs/logitech-g513.svg000066400000000000000000001653561467456234500174270ustar00rootroot00000000000000 Logitech G513 Keyboard for Piper image/svg+xml Logitech G513 Keyboard for Piper Owen D'Aprile piper-0.8/data/svgs/logitech-g600.svg000066400000000000000000002762701467456234500174220ustar00rootroot00000000000000 image/svg+xml piper-0.8/data/svgs/logitech-g602.svg000066400000000000000000001132041467456234500174070ustar00rootroot00000000000000 image/svg+xml G7 G8 G9 G4 G5 G6 G10 G11 piper-0.8/data/svgs/logitech-g603.svg000066400000000000000000000436711467456234500174220ustar00rootroot00000000000000 image/svg+xml piper-0.8/data/svgs/logitech-g604.svg000066400000000000000000001222301467456234500174100ustar00rootroot00000000000000 image/svg+xml G9 G8 G7 G6 G5 G4 piper-0.8/data/svgs/logitech-g700.svg000066400000000000000000001116071467456234500174130ustar00rootroot00000000000000 image/svg+xml piper-0.8/data/svgs/logitech-g703.svg000077700000000000000000000000001467456234500223752logitech-g403.svgustar00rootroot00000000000000piper-0.8/data/svgs/logitech-g705.svg000066400000000000000000000435251467456234500174230ustar00rootroot00000000000000 image/svg+xml piper-0.8/data/svgs/logitech-g815.svg000066400000000000000000003136171467456234500174270ustar00rootroot00000000000000 image/svg+xml piper-0.8/data/svgs/logitech-g9.svg000066400000000000000000000642221467456234500172550ustar00rootroot00000000000000 image/svg+xml piper-0.8/data/svgs/logitech-g900.svg000066400000000000000000000715001467456234500174120ustar00rootroot00000000000000 image/svg+xml piper-0.8/data/svgs/logitech-m500s.svg000066400000000000000000000501641467456234500176020ustar00rootroot00000000000000 image/svg+xml piper-0.8/data/svgs/logitech-m720.svg000066400000000000000000000536671467456234500174360ustar00rootroot00000000000000 image/svg+xml 1 2 3 piper-0.8/data/svgs/logitech-mx-anywhere2.svg000066400000000000000000000453461467456234500212720ustar00rootroot00000000000000 image/svg+xml piper-0.8/data/svgs/logitech-mx-anywhere2s.svg000077700000000000000000000000001467456234500262772logitech-mx-anywhere2.svgustar00rootroot00000000000000piper-0.8/data/svgs/logitech-mx-anywhere3.svg000066400000000000000000000450751467456234500212720ustar00rootroot00000000000000 image/svg+xml piper-0.8/data/svgs/logitech-mx-ergo.svg000066400000000000000000000624521467456234500203170ustar00rootroot00000000000000 image/svg+xml piper-0.8/data/svgs/logitech-mx-master-2s.svg000066400000000000000000000513011467456234500211670ustar00rootroot00000000000000 image/svg+xml piper-0.8/data/svgs/logitech-mx-master-3.svg000066400000000000000000000531011467456234500210050ustar00rootroot00000000000000 image/svg+xml piper-0.8/data/svgs/logitech-mx-master-3s.svg000066400000000000000000000531021467456234500211710ustar00rootroot00000000000000 image/svg+xml piper-0.8/data/svgs/logitech-mx-master.svg000077700000000000000000000000001467456234500254142logitech-mx-master-2s.svgustar00rootroot00000000000000piper-0.8/data/svgs/logitech-mx-vertical.svg000066400000000000000000000646711467456234500212010ustar00rootroot00000000000000 image/svg+xml piper-0.8/data/svgs/logitech-mx518.svg000066400000000000000000000421021467456234500176110ustar00rootroot00000000000000 image/svg+xml piper-0.8/data/svgs/marsgaming-mm4.svg000066400000000000000000001422721467456234500177640ustar00rootroot00000000000000 12 11 10 9 8 7 6 5 4 3 2 1 piper-0.8/data/svgs/roccat-kone-pure.svg000066400000000000000000000503161467456234500203170ustar00rootroot00000000000000 image/svg+xml piper-0.8/data/svgs/roccat-kone-xtd.svg000066400000000000000000000775311467456234500201530ustar00rootroot00000000000000 image/svg+xml piper-0.8/data/svgs/sn-tech-t3.svg000066400000000000000000000224501467456234500170240ustar00rootroot00000000000000 image/svg+xml piper-0.8/data/svgs/steelseries-kinzu-v2.svg000066400000000000000000000366471467456234500211660ustar00rootroot00000000000000 image/svg+xml piper-0.8/data/svgs/steelseries-kinzu-v3.svg000066400000000000000000000366271467456234500211650ustar00rootroot00000000000000 image/svg+xml piper-0.8/data/svgs/steelseries-rival.svg000066400000000000000000000544001467456234500206010ustar00rootroot00000000000000 image/svg+xml piper-0.8/data/svgs/steelseries-rival310.svg000066400000000000000000000564101467456234500210300ustar00rootroot00000000000000 image/svg+xml piper-0.8/data/svgs/steelseries-rival600.svg000066400000000000000000001026751467456234500210370ustar00rootroot00000000000000 image/svg+xml piper-0.8/data/svgs/steelseries-sensei310.svg000066400000000000000000000664361467456234500212120ustar00rootroot00000000000000 image/svg+xml piper-0.8/data/svgs/steelseries-senseiraw.svg000066400000000000000000000622221467456234500214650ustar00rootroot00000000000000 image/svg+xml piper-0.8/data/svgs/steelseries-senseiten.svg000066400000000000000000000664241467456234500214720ustar00rootroot00000000000000 image/svg+xml piper-0.8/data/svgs/svg-lookup.ini000066400000000000000000000142641467456234500172310ustar00rootroot00000000000000[ASUS ROG Chakram X] DeviceMatch=usb:0b05:1a18;usb:0b05:1a1a Svg=asus-rog-chakram-x.svg [ASUS ROG Gladius II Origin] DeviceMatch=usb:0b05:1877 Svg=asus-rog-gladius2-origin.svg [ASUS ROG Gladius II Origin PNK LTD] DeviceMatch=usb:0b05:18cd Svg=asus-rog-gladius2-origin-pink.svg [ASUS ROG Harpe Wireless] DeviceMatch=usb:0b05:1a92 Svg=asus-rog-harpe-wireless.svg [ASUS ROG Keris Wireless] DeviceMatch=usb:0b05:195e;usb:0b05:1960 Svg=asus-rog-keris-wireless.svg [ASUS ROG Keris Wireless AimPoint] DeviceMatch=usb:0b05:1a68 Svg=asus-rog-keris-wireless-aimpoint.svg [ASUS ROG Strix Carry] DeviceMatch=usb:0b05:18b4 Svg=asus-rog-strix-carry.svg [ASUS ROG Strix Impact II] DeviceMatch=usb:0b05:18e1 Svg=asus-rog-strix-impact2.svg [ASUS ROG Strix Impact II Wireless] DeviceMatch=usb:0b05:1949;usb:0b05:1947 Svg=asus-rog-strix-impact2-wireless.svg [Etekcity Scroll Alpha] DeviceMatch=usb:1ea7:4011 Svg=fallback.svg [Glorious Model D] DeviceMatch=usb:258a:0033 Svg=glorious-model-d.svg [Glorious Model O/O-] DeviceMatch=usb:258a:0036 Svg=glorious-model-o.svg [Logitech G102/G103] DeviceMatch=usb:046d:c084;usb:046d:c092;usb:046d:c09d Svg=logitech-g102-g203.svg [Logitech G300] DeviceMatch=usb:046d:c246 Svg=logitech-g300.svg [Logitech G302] DeviceMatch=usb:046d:c07f Svg=logitech-g303.svg [Logitech G303] DeviceMatch=usb:046d:c080 Svg=logitech-g303.svg [Logitech G303 Shroud Edition] DeviceMatch=usb:046d:c097 Svg=logitech-g303-se.svg [Logitech G305] DeviceMatch=usb:046d:4074 Svg=logitech-g-pro.svg [Logitech G402] DeviceMatch=usb:046d:c07e Svg=logitech-g402.svg [Logitech G403] DeviceMatch=usb:046d:c083 Svg=logitech-g403.svg [Logitech G403 Hero] DeviceMatch=usb:046d:c08f Svg=logitech-g403.svg [Logitech G403 Wireless] DeviceMatch=usb:046d:c082;usb:046d:405d Svg=logitech-g403.svg [Logitech G500] DeviceMatch=usb:046d:c068 Svg=logitech-g500.svg [Logitech G500s] DeviceMatch=usb:046d:c24e Svg=logitech-g500s.svg [Logitech G502 X Wireless] DeviceMatch=usb:046d:c098 Svg=logitech-g502-x.svg [Logitech G502 X] DeviceMatch=usb:046d:c099 Svg=logitech-g502-x.svg [Logitech G502 Hero Wireless] DeviceMatch=usb:046d:407f;usb:046d:c08d Svg=logitech-g502.svg [Logitech G502 Hero] DeviceMatch=usb:046d:c08b Svg=logitech-g502.svg [Logitech G502 Proteus Core] DeviceMatch=usb:046d:c07d Svg=logitech-g502.svg [Logitech G502 Proteus Spectrum] DeviceMatch=usb:046d:c332 Svg=logitech-g502.svg [Logitech G513 Carbon] DeviceMatch=usb:046d:c33c Svg=logitech-g513.svg [Logitech G600] DeviceMatch=usb:046d:c24a Svg=logitech-g600.svg [Logitech G602] DeviceMatch=usb:046d:402c Svg=logitech-g602.svg [Logitech G603] DeviceMatch=bluetooth:046d:b01c;usb:046d:406c Svg=logitech-g603.svg [Logitech G604] DeviceMatch=usb:046d:4085;bluetooth:046d:b024 Svg=logitech-g604.svg [Logitech G700] DeviceMatch=usb:046d:c06b;usb:046d:c07c Svg=logitech-g700.svg [Logitech G700s] DeviceMatch=usb:046d:c531 Svg=logitech-g700.svg [Logitech G703] DeviceMatch=usb:046d:c087;usb:046d:4070 Svg=logitech-g703.svg [Logitech G703 Hero] DeviceMatch=usb:046d:c090;usb:046d:4086 Svg=logitech-g703.svg [Logitech G705] DeviceMatch=usb:046d:c096;usb:046d:409d;bluetooth:046d:b02e Svg=logitech-g705.svg [Logitech G815] DeviceMatch=usb:046d:c33f Svg=logitech-g815.svg [Logitech G915] DeviceMatch=usb:046d:c33e;usb:046d:c541 Svg=logitech-g815.svg [Logitech G900] DeviceMatch=usb:046d:c081;usb:046d:4053 Svg=logitech-g900.svg [Logitech G903] DeviceMatch=usb:046d:c086;usb:046d:4067 Svg=logitech-g900.svg [Logitech G903 Hero] DeviceMatch=usb:046d:c091;usb:046d:4087 Svg=logitech-g900.svg [Logitech G9] DeviceMatch=usb:046d:c048 Svg=logitech-g9.svg [Logitech G9x] DeviceMatch=usb:046d:c066;usb:046d:c249 Svg=logitech-g9.svg [Logitech G Pro] DeviceMatch=usb:046d:c085;usb:046d:c08c Svg=logitech-g-pro.svg [Logitech G Pro Wireless] DeviceMatch=usb:046d:c088;usb:046d:4079 Svg=logitech-g-pro-wireless.svg [Logitech G Pro X Wireless Superlight] DeviceMatch=usb:046d:4093;usb:046d:c094 Svg=logitech-g-pro-x-wireless-superlight.svg [Logitech G Pro Keyboard] DeviceMatch=usb:046d:c339 Svg=logitech-g-pro-keyboard.svg [Logitech M500s] DeviceMatch=usb:046d:c093 Svg=logitech-m500s.svg [Logitech M720] DeviceMatch=usb:046d:405e;bluetooth:046d:b015 Svg=logitech-m720.svg [Logitech MX518] DeviceMatch=usb:046d:c08e Svg=logitech-mx518.svg [Logitech MX Anywhere 3] DeviceMatch=usb:046d:c52b;bluetooth:046d:b025 Svg=logitech-mx-anywhere3.svg [Logitech MX Anywhere 3B] DeviceMatch=bluetooth:046d:b02d Svg=logitech-mx-anywhere3.svg [Logitech MX Anywhere 2] DeviceMatch=usb:046d:404a;usb:046d:4072;usb:046d:4063;bluetooth:046d:b013;bluetooth:046d:b018;bluetooth:046d:b01f Svg=logitech-mx-anywhere2.svg [Logitech MX Anywhere 2S] DeviceMatch=bluetooth:046d:b01a;usb:046d:406a Svg=logitech-mx-anywhere2.svg [Logitech MX Ergo] DeviceMatch=bluetooth:046d:b01d;usb:046d:406f Svg=logitech-mx-ergo.svg [Logitech MX Master 3] DeviceMatch=bluetooth:046d:b023;usb:046d:4082 Svg=logitech-mx-master-3.svg [Logitech MX Master 3S] DeviceMatch=bluetooth:046d:b034 Svg=logitech-mx-master-3s.svg [Logitech MX Master 2S] DeviceMatch=bluetooth:046d:b019;usb:046d:4069 Svg=logitech-mx-master-2s.svg [Logitech MX Master] DeviceMatch=usb:046d:4041;bluetooth:046d:b012;usb:046d:4060;bluetooth:046d:b017;usb:046d:4071 Svg=logitech-mx-master.svg [Logitech MX Vertical] DeviceMatch=bluetooth:046d:b020;usb:046d:407b;usb:046d:c08a Svg=logitech-mx-vertical.svg [Mars Gaming MM4] DeviceMatch=usb:04d9:fa58 Svg=marsgaming-mm4.svg [Roccat Kone Pure] DeviceMatch=usb:1e7d:2dc2;usb:1e7d:2dbe Svg=roccat-kone-pure.svg [Roccat Kone XTD] DeviceMatch=usb:1e7d:2e22 Svg=roccat-kone-xtd.svg [SteelSeries Kinzu V2] DeviceMatch=usb:1038:1378 Svg=steelseries-kinzu-v2.svg [SteelSeries Kinzu V3] DeviceMatch=usb:1038:1388 Svg=steelseries-kinzu-v3.svg [SteelSeries Rival 310] DeviceMatch=usb:1038:1720 Svg=steelseries-rival310.svg [SteelSeries Rival 600] DeviceMatch=usb:1038:1724 Svg=steelseries-rival600.svg [SteelSeries Rival] DeviceMatch=usb:1038:1384 Svg=steelseries-rival.svg [SteelSeries Sensei 310] DeviceMatch=usb:1038:1722 Svg=steelseries-sensei310.svg [SteelSeries Sensei Raw] DeviceMatch=usb:1038:1369 Svg=steelseries-senseiraw.svg [SteelSeries Sensei Ten] DeviceMatch=usb:1038:1832 Svg=steelseries-senseiten.svg [SN Tech T3] DeviceMatch=usb:258a:0012 Svg=sn-tech-t3.svg piper-0.8/data/ui/000077500000000000000000000000001467456234500140465ustar00rootroot00000000000000piper-0.8/data/ui/AboutDialog.ui.in000066400000000000000000000025221467456234500172050ustar00rootroot00000000000000 False True normal Piper Version: @version@ https://github.com/libratbag/piper Visit Piper on GitHub translator-credits org.freedesktop.Piper gpl-2-0 False False False False 0 piper-0.8/data/ui/AdvancedPage.ui000066400000000000000000000300231467456234500167050ustar00rootroot00000000000000 piper-0.8/data/ui/ButtonDialog.ui000066400000000000000000000507431467456234500170110ustar00rootroot00000000000000 True False True True 18 vertical 6 True False 72 edit-find-symbolic True True 0 True False No button mapping found False True 1 True False Try a different search False True 2 piper-0.8/data/ui/ButtonRow.ui000066400000000000000000000026331467456234500163540ustar00rootroot00000000000000 piper-0.8/data/ui/DeviceRow.ui000066400000000000000000000031661467456234500163020ustar00rootroot00000000000000 piper-0.8/data/ui/ErrorPerspective.ui000066400000000000000000000055021467456234500177120ustar00rootroot00000000000000 True False Uh Oh! Something went wrong… False True piper-0.8/data/ui/LedDialog.ui000066400000000000000000000517651467456234500162470ustar00rootroot00000000000000 255 1 10 10000 100 500 piper-0.8/data/ui/MousePerspective.ui000066400000000000000000000206231467456234500177120ustar00rootroot00000000000000 False 2 True False vertical 6 True True in True True True False 180 True False Click to switch to another profile True True 0 Add profile True True True Add a new profile to the device False True 1 True False True True False stack True True True Select another profile popover_profiles True False Profile 1 center False True True True Commit the changes to the device True False Apply end 1 piper-0.8/data/ui/OptionButton.ui000066400000000000000000000046211467456234500170540ustar00rootroot00000000000000 piper-0.8/data/ui/ProfileRow.ui000066400000000000000000000043071467456234500165010ustar00rootroot00000000000000 piper-0.8/data/ui/ResolutionRow.ui000066400000000000000000000167371467456234500172560ustar00rootroot00000000000000 piper-0.8/data/ui/ResolutionsPage.ui000066400000000000000000000113571467456234500175370ustar00rootroot00000000000000 piper-0.8/data/ui/WelcomePerspective.ui000066400000000000000000000123431467456234500202150ustar00rootroot00000000000000 True False Select a Device False True piper-0.8/data/ui/Window.ui000066400000000000000000000031631467456234500156570ustar00rootroot00000000000000 app.about _About Piper piper-0.8/meson.build000066400000000000000000000125511467456234500146660ustar00rootroot00000000000000project('piper', version: '0.8', license: 'GPL-2.0-or-later', meson_version: '>= 0.51.0') # The tag date of the project_version(), update when the version bumps. version_date='2024-09-24' # The DBus API version of ratbagd that we are compatible with. Anything # higher or lower will not be compatible so make sure you bumpt that to the # latest released ratbagd version whenever a piper release is made. ratbagd_api_version = 2 # Options enable_runtime_dependency_checks = get_option('runtime-dependency-checks') # Dependencies if enable_runtime_dependency_checks ratbagd = find_program('ratbagd', required: false) ratbagd_required_version='0.18' if not ratbagd.found() message(''' ************************ ERROR *********************** * _???_ Dependency libratbag not found in $PATH! * *(_)_(_) ratbagd must be installed and running * * (o o) for Piper to work. * *==\o/== * ****************************************************** ''') else r = run_command(ratbagd, '--version') if r.returncode() != 0 or r.stdout().version_compare('<' + ratbagd_required_version) error(''' ************************ ERROR ***************************** * ( )( * * (\-. ) ( ) ratbagd found in $PATH is too * * / _`> .---------. old and will not work with * * _) / _)= |'-------'| this version of Piper. Please * *( / _/ |O O o| update libratbag/ratbagd. * * `-.__(___)_ | o O . o | * ************************************************************ ''') endif endif # external python modules that are required for running piper python_modules = [ 'lxml', 'evdev', 'cairo', 'gi', ] dependency('pygobject-3.0', required: true) else # external python modules that are required for building piper python_modules = ['lxml'] endif # Gtk version required gtk_major_version = 3 gtk_minor_version = 22 prefix = get_option('prefix') datadir = join_paths(prefix, get_option('datadir')) localedir = join_paths(prefix, get_option('localedir')) pkgdatadir = join_paths(datadir, meson.project_name()) bindir = join_paths(prefix, get_option('bindir')) podir = join_paths(meson.current_source_dir(), 'po') mandir = join_paths(prefix, get_option('mandir')) i18n = import('i18n') subdir('data') subdir('po') # Find the directory to install our Python code pymod = import('python') py3 = pymod.find_installation(modules: python_modules) python_dir = py3.get_install_dir() install_subdir('piper', install_dir: python_dir, exclude_directories: '__pycache__') config_piper = configuration_data() config_piper.set('pkgdatadir', pkgdatadir) config_piper.set('localedir', localedir) config_piper.set('gtk_major_version', gtk_major_version) config_piper.set('gtk_minor_version', gtk_minor_version) config_piper.set('RATBAGD_API_VERSION', ratbagd_api_version) config_piper.set('devel', '') config_piper_devel = config_piper config_piper_devel.set('pkgdatadir', join_paths(meson.current_build_dir(), 'data')) config_piper_devel.set('localedir', join_paths(meson.current_build_dir(), 'po')) config_piper_devel.set('devel', ''' sys.path.insert(1, '@0@') print('Running from source tree, using local files') '''.format(meson.current_source_dir())) configure_file(input: 'piper.in', output: 'piper', configuration: config_piper, install_dir: bindir) configure_file(input: 'piper.in', output: 'piper.devel', configuration: config_piper_devel) if meson.version().version_compare('>=0.59.0') gnome.post_install( gtk_update_icon_cache: true, update_desktop_database: true ) else meson.add_install_script('meson_install.sh') endif env_test = environment() # See: https://github.com/mesonbuild/meson/issues/3306. env_test.set('MESON_SOURCE_ROOT', meson.current_source_dir()) test_svg_files = find_program('tests/check-svg.py') test( 'check-svg', test_svg_files, args : join_paths(meson.current_source_dir(), 'data/svgs/'), env : ['BASEDIR=@0@'.format(join_paths(meson.current_source_dir(), 'data/'))], ) test( 'svg-lookup-check', find_program('tests/svg-lookup-ini-test.py'), args : [svg_mapping, join_paths(meson.current_source_dir(), 'data/svgs/')], ) test( 'files-in-git', find_program('tests/check-files-in-git.sh'), args : [meson.current_source_dir()], suite : ['all'], ) #### code formatting ##### run_target( 'python-black', command : 'tools/python-black.sh', ) python_black_check = find_program(join_paths(meson.current_source_dir(), 'tests/python-black-check.sh')) run_target( 'python-black-check', command : python_black_check, ) test( 'python-black-check', python_black_check, env: env_test, ) #### code linting ##### run_target( 'python-ruff', command : 'tools/python-ruff.sh', ) python_ruff_check = find_program(join_paths(meson.current_source_dir(), 'tests/python-ruff-check.sh')) run_target( 'python-ruff-check', command : python_ruff_check, ) test( 'python-ruff-check', python_ruff_check, env: env_test, ) piper-0.8/meson_install.sh000066400000000000000000000005041467456234500157220ustar00rootroot00000000000000#!/usr/bin/env sh if [ -z $DESTDIR ]; then PREFIX=${MESON_INSTALL_PREFIX:-/usr} # Update icon cache gtk-update-icon-cache -f -t $PREFIX/share/icons/hicolor # Update desktop database cache update-desktop-database # Install new schemas #glib-compile-schemas $PREFIX/share/glib-2.0/schemas/ fi piper-0.8/meson_options.txt000066400000000000000000000002261467456234500161550ustar00rootroot00000000000000option('runtime-dependency-checks', type: 'boolean', value: true, description: 'Check for runtime dependencies during installation (default=yes)') piper-0.8/org.freedesktop.Piper.json000066400000000000000000000043041467456234500175730ustar00rootroot00000000000000{ "app-id": "org.freedesktop.Piper", "runtime": "org.gnome.Platform", "runtime-version": "43", "sdk": "org.gnome.Sdk", "command": "piper", "finish-args": [ "--share=ipc", "--socket=x11", "--socket=wayland", "--system-talk-name=org.freedesktop.ratbag1", "--device=dri" ], "modules": [ { "name": "python-evdev", "buildsystem": "simple", "build-commands": [ "pip3 install --prefix=/app --no-deps ." ], "sources": [ { "type": "archive", "url": "https://files.pythonhosted.org/packages/dd/49/d75ac71f54c6c32ac3c63828541740db74d9c764a82496be97b82314d355/evdev-1.6.0.tar.gz", "sha256": "ecfa01b5c84f7e8c6ced3367ac95288f43cd84efbfd7dd7d0cdbfc0d18c87a6a" } ] }, { "name": "python-lxml", "buildsystem": "simple", "ensure-writable": [ "/app/lib/python*/site-packages/easy-install.pth", "/app/lib/python*/site-packages/setuptools.pth", "/lib/python*/site-packages/easy-install.pth", "/lib/python*/site-packages/setuptools.pth" ], "build-commands": [ "python3 setup.py build --with-cython", "python3 setup.py install --prefix=/app --root=/" ], "sources": [ { "type": "git", "url": "https://github.com/lxml/lxml.git", "tag": "lxml-4.9.1" }, { "type": "shell", "commands": [ "sed -i 's/if not platform_/if not dirs/' setup.py" ] } ] }, { "name": "Piper", "buildsystem": "meson", "config-opts": [ "-Druntime-dependency-checks=false" ], "sources": [ { "type": "git", "url": "https://github.com/libratbag/piper" } ] } ] } piper-0.8/piper.in000077500000000000000000000024161467456234500141750ustar00rootroot00000000000000#!/usr/bin/env python3 import gi import os import sys gi.require_version('Gio', '2.0') gi.require_version('Gtk', '3.0') from gi.repository import Gio, Gtk gtk_version = Gtk.get_major_version(), Gtk.get_minor_version() if gtk_version < (@gtk_major_version@, @gtk_minor_version@): print("Version of GTK is too old, @gtk_major_version@.@gtk_minor_version@ required", file=sys.stderr) sys.exit(1) @devel@ resource = Gio.resource_load(os.path.join('@pkgdatadir@', 'piper.gresource')) Gio.Resource._register(resource) def install_excepthook(): """Make sure we exit when an unhandled exception occurs.""" old_hook = sys.excepthook def new_hook(etype, evalue, etb): old_hook(etype, evalue, etb) while Gtk.main_level(): Gtk.main_quit() sys.exit() sys.excepthook = new_hook if __name__ == "__main__": import gettext import locale import signal from piper.application import Application install_excepthook() locale.bindtextdomain('piper', '@localedir@') locale.textdomain('piper') gettext.bindtextdomain('piper', '@localedir@') gettext.textdomain('piper') signal.signal(signal.SIGINT, signal.SIG_DFL) exit_status = Application(@RATBAGD_API_VERSION@).run(sys.argv) sys.exit(exit_status) piper-0.8/piper/000077500000000000000000000000001467456234500136375ustar00rootroot00000000000000piper-0.8/piper/__init__.py000066400000000000000000000000001467456234500157360ustar00rootroot00000000000000piper-0.8/piper/advancedpage.py000066400000000000000000000151121467456234500166130ustar00rootroot00000000000000# SPDX-License-Identifier: GPL-2.0-or-later import sys from typing import Optional import gi from .mousemap import MouseMap from .ratbagd import RatbagdDevice, RatbagdProfile from .util.gobject import connect_signal_with_weak_ref gi.require_version("Gtk", "3.0") from gi.repository import GObject, Gtk # noqa: E402 @Gtk.Template(resource_path="/org/freedesktop/Piper/ui/AdvancedPage.ui") class AdvancedPage(Gtk.Box): """ Advanced settings stack. """ __gtype_name__ = "AdvancedPage" angle_snapping: Gtk.Switch = Gtk.Template.Child() # type: ignore debounce: Gtk.ComboBox = Gtk.Template.Child() # type: ignore rate_1000: Gtk.RadioButton = Gtk.Template.Child() # type: ignore rate_125: Gtk.RadioButton = Gtk.Template.Child() # type: ignore rate_250: Gtk.RadioButton = Gtk.Template.Child() # type: ignore rate_500: Gtk.RadioButton = Gtk.Template.Child() # type: ignore rate_button_box: Gtk.ButtonBox = Gtk.Template.Child() # type: ignore def __init__( self, device: RatbagdDevice, profile: RatbagdProfile, *args, **kwargs ) -> None: """Instantiates a new AdvancedPage.""" Gtk.Box.__init__(self, *args, **kwargs) self._profile = profile cell = Gtk.CellRendererText() self.debounce.pack_start(cell, True) self.debounce.add_attribute(cell, "text", 0) model = Gtk.ListStore(str) for ms in profile.debounces: model.append([str(ms)]) self.debounce.set_model(model) self._handler_debounce = self.debounce.connect( "changed", self._on_debounce_combo_changed ) self._profile_debounce_time_changed_handler = connect_signal_with_weak_ref( self, self._profile, "notify::debounce", self._on_profile_debounce_time_changed, ) self._update_widget_debounce_time() are_report_rates_supported = ( profile.report_rate != 0 and len(profile.report_rates) != 0 ) self.rate_button_box.set_sensitive(are_report_rates_supported) self.rate_125.set_sensitive(125 in profile.report_rates) self.rate_250.set_sensitive(250 in profile.report_rates) self.rate_500.set_sensitive(500 in profile.report_rates) self.rate_1000.set_sensitive(1000 in profile.report_rates) self._handler_125 = self.rate_125.connect( "toggled", self._on_report_rate_toggled, 125 ) self._handler_250 = self.rate_250.connect( "toggled", self._on_report_rate_toggled, 250 ) self._handler_500 = self.rate_500.connect( "toggled", self._on_report_rate_toggled, 500 ) self._handler_1000 = self.rate_1000.connect( "toggled", self._on_report_rate_toggled, 1000 ) self._profile_report_rate_changed_handler = connect_signal_with_weak_ref( self, self._profile, "notify::report-rate", self._on_profile_report_rate_changed, ) self._update_widget_report_rate() profile = self._profile self._mousemap = MouseMap("#Buttons", device, spacing=20, border_width=20) self.pack_start(self._mousemap, True, True, 0) self._angle_snapping_switch_handler = self.angle_snapping.connect( "state-set", self._on_angle_snapping_switch_state_set ) self.angle_snapping.set_sensitive(profile.angle_snapping != -1) self._profile_angle_snapping_changed_handler = connect_signal_with_weak_ref( self, self._profile, "notify::angle-snapping", self._on_profile_angle_snapping_changed, ) self._update_widget_angle_snapping() self.show_all() def _on_profile_debounce_time_changed( self, profile: RatbagdProfile, pspec: Optional[GObject.ParamSpec] ) -> None: self._update_widget_debounce_time() def _update_widget_debounce_time(self) -> None: profile = self._profile with self.debounce.handler_block(self._handler_debounce): if profile.debounce in profile.debounces: idx = profile.debounces.index(profile.debounce) self.debounce.set_active(idx) else: self.debounce.set_active(0) def _on_debounce_combo_changed(self, combo: Gtk.ComboBox) -> None: idx = combo.get_active() profile = self._profile with profile.handler_block(self._profile_debounce_time_changed_handler): profile.debounce = profile.debounces[idx] def _on_angle_snapping_switch_state_set( self, button: Gtk.Switch, state: bool ) -> None: profile = self._profile with profile.handler_block(self._profile_angle_snapping_changed_handler): profile.angle_snapping = 1 if state else 0 def _on_profile_angle_snapping_changed( self, profile: RatbagdProfile, pspec: Optional[GObject.ParamSpec] ) -> None: self._update_widget_angle_snapping() def _update_widget_angle_snapping(self) -> None: with self.angle_snapping.handler_block(self._angle_snapping_switch_handler): self.angle_snapping.set_active(self._profile.angle_snapping == 1) def _on_report_rate_toggled(self, button: Gtk.RadioButton, rate: int) -> None: if not button.get_active(): return profile = self._profile with profile.handler_block(self._profile_report_rate_changed_handler): profile.report_rate = rate def _on_profile_report_rate_changed( self, profile: RatbagdProfile, pspec: Optional[GObject.ParamSpec] ) -> None: self._update_widget_report_rate() def _update_widget_report_rate(self) -> None: with self.rate_125.handler_block(self._handler_125): if self._profile.report_rate == 125: self.rate_125.set_active(True) return with self.rate_250.handler_block(self._handler_250): if self._profile.report_rate == 250: self.rate_250.set_active(True) return with self.rate_500.handler_block(self._handler_500): if self._profile.report_rate == 500: self.rate_500.set_active(True) return with self.rate_1000.handler_block(self._handler_1000): if self._profile.report_rate == 1000: self.rate_1000.set_active(True) return # TODO: think how we should handle this. print( f"Profile was set to a weird report rate: {self._profile.report_rate}", file=sys.stderr, ) piper-0.8/piper/application.py000066400000000000000000000051631467456234500165210ustar00rootroot00000000000000# SPDX-License-Identifier: GPL-2.0-or-later from typing import Optional from .ratbagd import Ratbagd from .window import Window import gi gi.require_version("Gio", "2.0") gi.require_version("Gtk", "3.0") from gi.repository import Gio, GLib, Gtk # noqa class Application(Gtk.Application): """A Gtk.Application subclass to handle the application's initialization and integration with the GNOME stack. It implements the do_startup and do_activate methods and is responsible for the application's menus, icons, title and lifetime.""" def __init__(self, ratbagd_api_version: int) -> None: """Instantiates a new Application.""" Gtk.Application.__init__( self, application_id="org.freedesktop.Piper", flags=Gio.ApplicationFlags.FLAGS_NONE, ) GLib.set_application_name("Piper") self._required_ratbagd_version = ratbagd_api_version def do_startup(self) -> None: """This function is called when the application is first started. All initialization should be done here, to prevent doing duplicate work in case another window is opened.""" Gtk.Application.do_startup(self) self._build_app_menu() self._ratbagd: Optional[Ratbagd] = None def init_ratbagd(self) -> Ratbagd: if self._ratbagd is None: self._ratbag = Ratbagd(self._required_ratbagd_version) return self._ratbag def do_activate(self) -> None: """This function is called when the user requests a new window to be opened.""" window = Window(self.init_ratbagd, application=self) window.present() def _build_app_menu(self) -> None: # Set up the app menu actions = [("about", self._about), ("quit", self._quit)] for name, callback in actions: action = Gio.SimpleAction.new(name, None) action.connect("activate", callback) self.add_action(action) def _about(self, action: Gio.SimpleAction, param: None) -> None: # Set up the about dialog. builder = Gtk.Builder().new_from_resource( "/org/freedesktop/Piper/AboutDialog.ui" ) about: Optional[Gtk.AboutDialog] = builder.get_object("about_dialog") # type: ignore assert about is not None about.set_transient_for(self.get_active_window()) about.connect("response", lambda about, param: about.destroy()) about.show() def _quit(self, action: Gio.SimpleAction, param: None) -> None: # Quit the application. windows = self.get_windows() for window in windows: window.destroy() piper-0.8/piper/buttondialog.py000066400000000000000000000401501467456234500167040ustar00rootroot00000000000000# SPDX-License-Identifier: GPL-2.0-or-later import sys from gettext import gettext as _ from typing import List, Optional, Tuple, Union from .ratbagd import RatbagdButton, RatbagdMacro, RatbagDeviceType import gi gi.require_version("Gtk", "3.0") from gi.repository import Gdk, GdkX11, GObject, Gtk # noqa @Gtk.Template(resource_path="/org/freedesktop/Piper/ui/ButtonRow.ui") class ButtonRow(Gtk.ListBoxRow): """A Gtk.ListBoxRow subclass to implement the rows that show up in the ButtonDialog's Gtk.ListBox. It doesn't do much besides moving UI code into a .ui file.""" __gtype_name__ = "ButtonRow" description_label: Gtk.Label = Gtk.Template.Child() # type: ignore def __init__( self, description: str, section: str, action_type: RatbagdButton.ActionType, value: Union[int, RatbagdButton.ActionSpecial, None], *args, **kwargs, ) -> None: """Instantiates a new ButtonRow. @param description The text to display in the row, as str. @param section The section this row belongs to, as str. @param action_type The type of this row's mapping, as one of RatbagdButton.ActionType.*. @param value The value to set when this row is activated. The type needs to match the action_type, e.g. for it should be int for RatbagdButton.ActionType.BUTTON. """ Gtk.ListBoxRow.__init__(self, *args, **kwargs) self._section = section self._action_type = action_type self._value = value self.description_label.set_text(description) @GObject.Property def description(self) -> str: return self.description_label.get_text() @Gtk.Template(resource_path="/org/freedesktop/Piper/ui/ButtonDialog.ui") class ButtonDialog(Gtk.Dialog): """A Gtk.Dialog subclass to implement the dialog that shows the configuration options for button mappings.""" __gtype_name__ = "ButtonDialog" LEFT_HANDED_MODE = -1000 RIGHT_HANDED_MODE = -1001 # Gdk uses an offset of 8 from the keycodes defined in linux/input.h. _XORG_KEYCODE_OFFSET = 8 empty_search_placeholder: Gtk.Box = Gtk.Template.Child() # type: ignore label_keystroke: Gtk.Label = Gtk.Template.Child() # type: ignore label_preview: Gtk.Label = Gtk.Template.Child() # type: ignore listbox: Gtk.ListBox = Gtk.Template.Child() # type: ignore radio_left_handed: Gtk.RadioButton = Gtk.Template.Child() # type: ignore radio_right_handed: Gtk.RadioButton = Gtk.Template.Child() # type: ignore row_keystroke: Gtk.ListBoxRow = Gtk.Template.Child() # type: ignore row_keystroke_label: Gtk.Label = Gtk.Template.Child() # type: ignore search_bar: Gtk.SearchBar = Gtk.Template.Child() # type: ignore search_entry: Gtk.SearchEntry = Gtk.Template.Child() # type: ignore stack: Gtk.Stack = Gtk.Template.Child() # type: ignore def __init__( self, ratbagd_button: RatbagdButton, buttons: List[RatbagdButton], device_type: RatbagDeviceType, *args, **kwargs, ) -> None: """Instantiates a new ButtonDialog. @param ratbagd_button The button to configure, as ratbagd.RatbagdButton. @param buttons The buttons on this device, as [ratbagd.RatbagdButton]. @param devicetype The type of this device, as ratbagd.RatbagDeviceType. """ Gtk.Dialog.__init__(self, *args, **kwargs) self._grab_pointer: Optional[Gdk.Device] = None self._current_macro: Optional[RatbagdMacro] = None self._button = ratbagd_button self._device_type = device_type self._action_type = self._button.action_type if self.action_type == RatbagdButton.ActionType.NONE: self._mapping = None elif self._action_type == RatbagdButton.ActionType.BUTTON: self._mapping = self._button.mapping elif self._action_type == RatbagdButton.ActionType.MACRO: self._mapping = self._button.macro elif self._action_type == RatbagdButton.ActionType.KEY: self._mapping = self._button.key elif self._action_type == RatbagdButton.ActionType.SPECIAL: self._mapping = self._button.special else: self._mapping = -1 self._init_ui(buttons) def _init_ui(self, buttons: List[RatbagdButton]) -> None: if self._device_type is RatbagDeviceType.MOUSE and self._button.index in [0, 1]: self._init_primary_buttons_ui() else: self._init_other_buttons_ui(buttons) def _init_primary_buttons_ui(self) -> None: # Shows the listbox to swap the primary buttons. self.stack.set_visible_child_name("handedness") # Left mouse button (index 0) is mapped to right mouse button, where # mappings are 1-indexed and thus right mouse click has value 2. # Or, right mouse button (index 1) is mapped to left mouse button, # which has value 1. if ( self._button.index == 0 and self._mapping == 2 or self._button.index == 1 and self._mapping == 1 ): self.radio_left_handed.set_active(True) else: self.radio_right_handed.set_active(True) def _init_other_buttons_ui(self, buttons: List[RatbagdButton]) -> None: # Shows the listbox to map non-primary buttons. self.listbox.set_header_func(self._listbox_header_func) self.listbox.set_filter_func(self._listbox_filter_func) self.listbox.set_placeholder(self.empty_search_placeholder) self.search_entry.connect( "notify::text", lambda o, p: self.listbox.invalidate_filter() ) i = 0 for button in buttons: key, name = self._get_button_name_and_description(button) # Translators: section header for mapping one button's click to another. row = ButtonRow( name, _("Button mapping"), RatbagdButton.ActionType.BUTTON, button.index + 1, ) self.listbox.insert(row, i) if ( self._action_type == RatbagdButton.ActionType.BUTTON and button.index + 1 == self._button.mapping ): self.listbox.select_row(row) i += 1 for key, name in RatbagdButton.SPECIAL_DESCRIPTION.items(): if name in ["Unknown", "Invalid"]: continue # Translators: section header for assigning special functions to buttons. row = ButtonRow( _(name), _("Special mapping"), RatbagdButton.ActionType.SPECIAL, key ) self.listbox.insert(row, i) if ( self._action_type == RatbagdButton.ActionType.SPECIAL and key == self._mapping ): self.listbox.select_row(row) i += 1 row = ButtonRow(_("Disable"), _("Other"), RatbagdButton.ActionType.NONE, None) row.set_sensitive(RatbagdButton.ActionType.NONE in self._button.action_types) self.listbox.insert(row, i) i += 1 if self._action_type == RatbagdButton.ActionType.NONE: self.listbox.select_row(row) if self._action_type == RatbagdButton.ActionType.MACRO: self._create_current_macro(macro=self._mapping) elif self._action_type == RatbagdButton.ActionType.KEY: macro = RatbagdMacro() macro.append(RatbagdButton.Macro.KEY_PRESS, self._mapping) macro.append(RatbagdButton.Macro.KEY_RELEASE, self._mapping) self._create_current_macro(macro=macro) else: self._create_current_macro() def _create_current_macro(self, macro: Optional[RatbagdMacro] = None) -> None: if macro is not None: self._current_macro = macro self._on_macro_updated(macro, None) else: self._current_macro = RatbagdMacro() self._current_macro.connect("macro-set", self._on_macro_set) self._current_macro.connect("notify::keys", self._on_macro_updated) def _listbox_header_func(self, row: ButtonRow, before: ButtonRow) -> None: # Adds headers to those rows where a new category starts, to separate # different kinds of mappings. if row == self.row_keystroke: separator = Gtk.Separator( orientation=Gtk.Orientation.HORIZONTAL, margin_top=18 ) row.set_header(separator) return add_header = row._section != before._section if before is not None else True if not add_header: row.set_header(None) return box = Gtk.Box.new(orientation=Gtk.Orientation.VERTICAL, spacing=6) if before is not None: box.set_margin_top(18) else: box.set_margin_top(6) markup = f"{row._section}" label = Gtk.Label(label=markup, use_markup=True, xalign=0.0, margin_start=6) label.get_style_context().add_class("dim-label") box.add(label) box.add(Gtk.Separator(orientation=Gtk.Orientation.HORIZONTAL)) row.set_header(box) box.show_all() def _listbox_filter_func(self, row: Gtk.ListBoxRow) -> bool: # Filters the list box with the text from the search entry. if self.search_entry.get_text_length() == 0: return True if row is not self.row_keystroke: description = row.description.casefold() else: description = self.row_keystroke_label.get_label().casefold() search = self.search_entry.get_text().casefold() return all(term in description for term in search.split(" ")) def _get_button_name_and_description( self, button: RatbagdButton ) -> Tuple[str, str]: # Translators: the {} will be replaced with the button index, e.g. # "Button 1 click". name = _("Button {} click").format(button.index) if button.index in RatbagdButton.BUTTON_DESCRIPTION: description = _(RatbagdButton.BUTTON_DESCRIPTION[button.index]) else: description = name return name, description def _grab_seat(self) -> bool: """ Grabs the keyboard seat. Returns True on success, False on failure. Gratefully copied from GNOME Control Center's keyboard panel. """ window = self.get_window() assert window is not None display = window.get_display() seat: Gdk.Seat = display.get_default_seat() status = seat.grab( window, Gdk.SeatCapabilities.KEYBOARD, False, None, None, None, None ) if status != Gdk.GrabStatus.SUCCESS: return False pointer = seat.get_keyboard() assert pointer is not None self._grab_pointer = pointer self.grab_add() return True def _release_grab(self) -> None: # Releases a previously grabbed keyboard seat, if any. if self._grab_pointer is None: return self._grab_pointer.get_seat().ungrab() self._grab_pointer = None self.grab_remove() def do_key_press_event(self, event: Gdk.Event) -> bool: # Overrides Gtk.Window's standard key press event callback, so we can # capture the pressed buttons in capture mode. If we're not in capture # mode, we trigger the search bar on any key press. if self.stack.get_visible_child_name() != "capture": if self.search_bar.handle_event(event) == Gdk.EVENT_STOP: return Gdk.EVENT_STOP return Gtk.Window.do_key_press_event(self, event) return self._do_key_event(event) def do_key_release_event(self, event: Gdk.Event) -> bool: # Overrides Gtk.Window's standard key release event callback, so we can # capture the released buttons in capture mode. If we're not in capture # mode, we pass the event on to other widgets in the dialog. if self.stack.get_visible_child_name() != "capture": return Gtk.Window.do_key_release_event(self, event) return self._do_key_event(event) def _do_key_event(self, event: Gdk.Event) -> bool: # Normalize tab. if event.keyval == Gdk.KEY_ISO_Left_Tab: event.keyval = Gdk.KEY_Tab # HACK: we don't want to use SysRq as a keybinding, but we do want # Al+Print, so we avoid translating Alt+Print to SysRq. if event.keyval == Gdk.KEY_Sys_Req and ( event.state & Gdk.ModifierType.MOD1_MASK ): event.keyval = Gdk.KEY_Print if event.type == Gdk.EventType.KEY_PRESS: type = RatbagdButton.Macro.KEY_PRESS elif event.type == Gdk.EventType.KEY_RELEASE: type = RatbagdButton.Macro.KEY_RELEASE else: raise ValueError("Incorrect event type") # TODO: this needs to be checked for its Wayland support. if not self._XORG_KEYCODE_OFFSET <= event.hardware_keycode <= 255: print("Keycode is not within the valid range.", file=sys.stderr) else: assert self._current_macro is not None self._current_macro.append( type, event.hardware_keycode - self._XORG_KEYCODE_OFFSET ) return Gdk.EVENT_STOP def _on_macro_updated( self, macro: RatbagdMacro, pspec: Optional[GObject.ParamSpec] ) -> None: current_macro = str(self._current_macro) self.label_keystroke.set_label(current_macro) self.label_preview.set_label(current_macro) def _on_macro_set(self, macro: RatbagdMacro) -> None: # A macro has been set; update accordingly. if ( RatbagdButton.ActionType.KEY in self._button.action_types and len(macro.keys) == 2 ): # single key (press + release events) self._action_type = RatbagdButton.ActionType.KEY type_, value = macro.keys[0] self._mapping = value else: self._action_type = RatbagdButton.ActionType.MACRO self._mapping = macro self.stack.set_visible_child_name("overview") self._release_grab() @Gtk.Template.Callback("_on_row_activated") def _on_row_activated(self, _listbox: Gtk.ListBox, row: ButtonRow) -> None: if row == self.row_keystroke: if self._grab_seat() is not True: # TODO: display this somewhere in the UI instead. print("Unable to grab keyboard, can't set keystroke", file=sys.stderr) else: self._create_current_macro() self.stack.set_visible_child_name("capture") else: self._action_type = row._action_type self._mapping = row._value @Gtk.Template.Callback("_on_apply_button_clicked") def _on_apply_button_clicked(self, button: Gtk.Button) -> Optional[bool]: if self.stack.get_visible_child_name() == "capture": assert self._current_macro is not None self._current_macro.accept() return Gdk.EVENT_PROPAGATE @Gtk.Template.Callback("_on_primary_mode_toggled") def _on_primary_mode_toggled(self, toggle: Gtk.RadioButton) -> None: if not toggle.get_active(): return self._action_type = RatbagdButton.ActionType.BUTTON if toggle is self.radio_left_handed: self._mapping = ButtonDialog.LEFT_HANDED_MODE elif toggle is self.radio_right_handed: self._mapping = ButtonDialog.RIGHT_HANDED_MODE @GObject.Property def action_type(self) -> RatbagdButton.ActionType: """The action type as last set in the dialog, one of RatbagdButton.ActionType.*.""" return self._action_type @GObject.Property def mapping(self) -> Union[RatbagdMacro, int]: """The mapping as last set in the dialog. Note that the type depends on action_type, and as such you should check that before using this property. A custom value of ButtonDialog.LEFT_HANDED_MODE means that the left- and right mouse buttons should be swapped, whereas ButtonDialog.RIGHT_HANDED_MODE means that the buttons should be as usual.""" return self._mapping piper-0.8/piper/buttonspage.py000066400000000000000000000163451467456234500165550ustar00rootroot00000000000000# SPDX-License-Identifier: GPL-2.0-or-later from gettext import gettext as _ from typing import Optional from .buttondialog import ButtonDialog from .mousemap import MouseMap from .optionbutton import OptionButton from .ratbagd import ( RatbagdButton, RatbagdDevice, RatbagdProfile, evcode_to_str, ) from .util.gobject import connect_signal_with_weak_ref import gi gi.require_version("Gtk", "3.0") from gi.repository import Gtk, GObject # noqa class ButtonsPage(Gtk.Box): """The second stack page, exposing the button configuration.""" __gtype_name__ = "ButtonsPage" def __init__( self, ratbagd_device: RatbagdDevice, profile: RatbagdProfile, *args, **kwargs ) -> None: """Instantiates a new ButtonsPage. @param ratbag_device The ratbag device to configure, as ratbagd.RatbagdDevice """ Gtk.Box.__init__(self, *args, **kwargs) self._device = ratbagd_device self._profile = profile self._mousemap = MouseMap("#Buttons", self._device, spacing=20, border_width=20) self.pack_start(self._mousemap, True, True, 0) self._sizegroup = Gtk.SizeGroup(mode=Gtk.SizeGroupMode.HORIZONTAL) for ratbagd_button in profile.buttons: button = OptionButton() # Set the correct label in the option button. self._on_button_mapping_changed(ratbagd_button, None, button) button.connect("clicked", self._on_button_clicked, ratbagd_button) connect_signal_with_weak_ref( self, ratbagd_button, "notify::mapping", self._on_button_mapping_changed, button, ) connect_signal_with_weak_ref( self, ratbagd_button, "notify::special", self._on_button_mapping_changed, button, ) connect_signal_with_weak_ref( self, ratbagd_button, "notify::macro", self._on_button_mapping_changed, button, ) connect_signal_with_weak_ref( self, ratbagd_button, "notify::key", self._on_button_mapping_changed, button, ) connect_signal_with_weak_ref( self, ratbagd_button, "notify::action-type", self._on_button_mapping_changed, button, ) self._mousemap.add(button, f"#button{ratbagd_button.index}") self._sizegroup.add_widget(button) self.show_all() def _on_button_mapping_changed( self, ratbagd_button: RatbagdButton, pspec: Optional[GObject.ParamSpec], optionbutton: OptionButton, ) -> None: # Called when the button's action type changed, which means its # corresponding optionbutton has to be updated. action_type = ratbagd_button.action_type if action_type == RatbagdButton.ActionType.BUTTON: if ratbagd_button.mapping - 1 in RatbagdButton.BUTTON_DESCRIPTION: label = _(RatbagdButton.BUTTON_DESCRIPTION[ratbagd_button.mapping - 1]) else: # Translators: the {} will be replaced with the button index, e.g. # "Button 1 click". label = _("Button {} click").format(ratbagd_button.mapping - 1) elif action_type == RatbagdButton.ActionType.SPECIAL: label = _(RatbagdButton.SPECIAL_DESCRIPTION[ratbagd_button.special]) elif action_type == RatbagdButton.ActionType.MACRO: label = _("Macro: {}").format(str(ratbagd_button.macro)) elif action_type == RatbagdButton.ActionType.KEY: label = _("Key: {}").format(evcode_to_str(ratbagd_button.key)) elif action_type == RatbagdButton.ActionType.NONE: # Translators: the button is turned disabled, e.g. off. label = _("Disabled") else: # Translators: the button has an unknown function. label = _("Unknown") optionbutton.set_label(label) def _on_button_clicked( self, button: OptionButton, ratbagd_button: RatbagdButton ) -> None: # Presents the ButtonDialog to configure the mouse button corresponding # to the clicked button. buttons = self._profile.buttons device_type = self._device.device_type dialog = ButtonDialog( ratbagd_button, buttons, device_type, title=_("Configure button {}").format(ratbagd_button.index), use_header_bar=True, transient_for=self.get_toplevel(), ) dialog.connect("response", self._on_dialog_response, ratbagd_button) dialog.present() def _on_dialog_response( self, dialog: ButtonDialog, response: Gtk.ResponseType, ratbagd_button: RatbagdButton, ) -> None: # The user either pressed cancel or apply. If it's apply, apply the # changes before closing the dialog, otherwise just close the dialog. if response == Gtk.ResponseType.APPLY: if dialog.action_type == RatbagdButton.ActionType.NONE: ratbagd_button.disable() elif dialog.action_type == RatbagdButton.ActionType.BUTTON: if dialog.mapping in [ ButtonDialog.LEFT_HANDED_MODE, ButtonDialog.RIGHT_HANDED_MODE, ]: left = self._find_button_type(0) right = self._find_button_type(1) if left is None or right is None: return # Mappings are 1-indexed, so 1 is left mouse click and 2 is # right mouse click. if dialog.mapping == ButtonDialog.LEFT_HANDED_MODE: left.mapping, right.mapping = 2, 1 elif dialog.mapping == ButtonDialog.RIGHT_HANDED_MODE: left.mapping, right.mapping = 1, 2 else: ratbagd_button.mapping = dialog.mapping elif dialog.action_type == RatbagdButton.ActionType.MACRO: ratbagd_button.macro = dialog.mapping elif dialog.action_type == RatbagdButton.ActionType.KEY: ratbagd_button.key = dialog.mapping elif dialog.action_type == RatbagdButton.ActionType.SPECIAL: ratbagd_button.special = dialog.mapping lower = RatbagdButton.ActionSpecial.PROFILE_CYCLE_UP upper = RatbagdButton.ActionSpecial.PROFILE_DOWN if lower <= dialog.mapping <= upper: index = ratbagd_button.index for profile in self._device.profiles: if profile is self._profile: continue profile.buttons[index].special = dialog.mapping dialog.destroy() def _find_button_type(self, button_type: int) -> Optional[RatbagdButton]: for button in self._profile.buttons: if button.index == button_type: return button return None piper-0.8/piper/devicerow.py000066400000000000000000000037371467456234500162120ustar00rootroot00000000000000# SPDX-License-Identifier: GPL-2.0-or-later from piper.svg import get_svg import sys import gi from .ratbagd import RatbagdDevice gi.require_version("Gtk", "3.0") from gi.repository import GdkPixbuf, GObject, Gtk, Rsvg # noqa @Gtk.Template(resource_path="/org/freedesktop/Piper/ui/DeviceRow.ui") class DeviceRow(Gtk.ListBoxRow): """A Gtk.ListBoxRow subclass to present devices in the welcome perspective.""" __gtype_name__ = "DeviceRow" image: Gtk.Image = Gtk.Template.Child() # type: ignore title: Gtk.Label = Gtk.Template.Child() # type: ignore def __init__(self, device: RatbagdDevice, *args, **kwargs) -> None: Gtk.ListBoxRow.__init__(self, *args, **kwargs) self._device = device fw_version = device.firmware_version if fw_version: self.title.set_markup( f"{device.name} (firmware {fw_version})" ) else: self.title.set_text(device.name) try: svg_bytes = get_svg(device.model) assert svg_bytes is not None handle = Rsvg.Handle.new_from_data(svg_bytes) assert handle is not None svg = handle.get_pixbuf_sub("#Device") handle.close() if svg is None: print( f"Device {device.name}'s SVG is incompatible", file=sys.stderr, ) else: svg = svg.scale_simple(50, 50, GdkPixbuf.InterpType.BILINEAR) if svg is None: print("Cannot resize device SVG", file=sys.stderr) else: self.image.set_from_pixbuf(svg) except FileNotFoundError: print( f"Device {device.name} has no image or its path is invalid", file=sys.stderr, ) self.show_all() @GObject.Property def device(self) -> RatbagdDevice: return self._device piper-0.8/piper/errorperspective.py000066400000000000000000000036321467456234500176200ustar00rootroot00000000000000# SPDX-License-Identifier: GPL-2.0-or-later from typing import Optional import gi gi.require_version("Gtk", "3.0") from gi.repository import GObject, Gtk # noqa @Gtk.Template(resource_path="/org/freedesktop/Piper/ui/ErrorPerspective.ui") class ErrorPerspective(Gtk.Box): """A perspective to present an error condition in a user-friendly manner.""" __gtype_name__ = "ErrorPerspective" label_error: Gtk.Label = Gtk.Template.Child() # type: ignore label_detail: Gtk.Label = Gtk.Template.Child() # type: ignore _titlebar: Gtk.HeaderBar = Gtk.Template.Child() # type: ignore def __init__(self, message: Optional[str] = None, *args, **kwargs) -> None: """Instantiates a new ErrorPerspective. @param message The error message to display, as str. """ Gtk.Box.__init__(self, *args, **kwargs) if message is not None: self.set_message(message) @GObject.Property def name(self) -> str: """The name of this perspective.""" return "error_perspective" @GObject.Property def titlebar(self) -> Gtk.Widget: """The titlebar to this perspective.""" return self._titlebar @GObject.Property def can_go_back(self) -> bool: """Whether this perspective wants a back button to be displayed in case there is more than one connected device.""" return False @GObject.Property def can_shutdown(self) -> bool: """Whether this perspective can safely shutdown.""" return True def set_message(self, message: str) -> None: """Sets the error message. @param message The error message to display, as str. """ self.label_error.set_label(message) def set_detail(self, detail: str) -> None: """Sets the detail message. @param message The detail message to display, as str. """ self.label_detail.set_label(detail) piper-0.8/piper/leddialog.py000066400000000000000000000073431467456234500161440ustar00rootroot00000000000000# SPDX-License-Identifier: GPL-2.0-or-later from typing import Tuple from .ratbagd import RatbagdLed import gi gi.require_version("Gtk", "3.0") from gi.repository import Gdk, GObject, Gtk # noqa @Gtk.Template(resource_path="/org/freedesktop/Piper/ui/LedDialog.ui") class LedDialog(Gtk.Dialog): """A Gtk.Dialog subclass to implement the dialog that shows the configuration options for the LED effects.""" __gtype_name__ = "LedDialog" adjustment_brightness: Gtk.Adjustment = Gtk.Template.Child() # type: ignore adjustment_effect_duration: Gtk.Adjustment = Gtk.Template.Child() # type: ignore colorbutton: Gtk.ColorButton = Gtk.Template.Child() # type: ignore colorchooser: Gtk.ColorChooserWidget = Gtk.Template.Child() # type: ignore led_off_image: Gtk.Image = Gtk.Template.Child() # type: ignore stack: Gtk.Stack = Gtk.Template.Child() # type: ignore titlebar: Gtk.HeaderBar = Gtk.Template.Child() # type: ignore def __init__(self, ratbagd_led: RatbagdLed, *args, **kwargs) -> None: """Instantiates a new LedDialog. @param ratbagd_led The LED to configure, as ratbagd.RatbagdLed. """ Gtk.Dialog.__init__(self, *args, **kwargs) self._led = ratbagd_led self._modes = { "solid": RatbagdLed.Mode.ON, "cycle": RatbagdLed.Mode.CYCLE, "breathing": RatbagdLed.Mode.BREATHING, "off": RatbagdLed.Mode.OFF, } # FIXME: why is this needed if this child's type is `titlebar` already? self.set_titlebar(self.titlebar) mode = self._led.mode for k, v in self._modes.items(): if mode == v: self.stack.set_visible_child_name(k) if v not in self._led.modes: child = self.stack.get_child_by_name(k) assert child is not None child.set_visible(False) rgba = self._get_led_color_as_rgba() self.colorchooser.set_rgba(rgba) self.colorbutton.set_rgba(rgba) self.adjustment_brightness.set_value(self._led.brightness) self.adjustment_effect_duration.set_value(self._led.effect_duration) sp = Gtk.CssProvider() sp.load_from_data(b"* { background: #565854}") Gtk.StyleContext.add_provider( self.led_off_image.get_style_context(), sp, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION, ) @Gtk.Template.Callback("_on_change_value") def _on_change_value( self, scale: Gtk.Scale, scroll: Gtk.ScrollType, value: float ) -> bool: # Work around the Gtk.Scale not snapping to its step increment. step = scale.get_adjustment().get_step_increment() scale.set_value(int(round(value / step) * step)) return True def _get_led_color_as_rgba(self) -> Gdk.RGBA: # Helper function to convert ratbagd's 0-255 color range to a Gdk.RGBA # with a 0.0-1.0 color range. r, g, b = self._led.color return Gdk.RGBA(r / 255.0, g / 255.0, b / 255.0, 1.0) @GObject.Property def mode(self) -> RatbagdLed.Mode: visible_child = self.stack.get_visible_child_name() assert visible_child is not None return self._modes[visible_child] @GObject.Property def color(self) -> Tuple[float, float, float]: if self.mode == RatbagdLed.Mode.ON: rgba = self.colorchooser.get_rgba() else: rgba = self.colorbutton.get_rgba() return (rgba.red * 255.0, rgba.green * 255.0, rgba.blue * 255.0) @GObject.Property def brightness(self) -> float: return self.adjustment_brightness.get_value() @GObject.Property def effect_duration(self) -> float: return self.adjustment_effect_duration.get_value() piper-0.8/piper/ledspage.py000066400000000000000000000052401467456234500157760ustar00rootroot00000000000000# SPDX-License-Identifier: GPL-2.0-or-later from gettext import gettext as _ from typing import Optional from .leddialog import LedDialog from .mousemap import MouseMap from .optionbutton import OptionButton from .ratbagd import RatbagdDevice, RatbagdLed, RatbagdProfile from .util.gobject import connect_signal_with_weak_ref import gi gi.require_version("Gtk", "3.0") from gi.repository import Gtk, GObject # noqa class LedsPage(Gtk.Box): """The third stack page, exposing the LED configuration.""" __gtype_name__ = "LedsPage" def __init__( self, ratbagd_device: RatbagdDevice, profile: RatbagdProfile, *args, **kwargs ) -> None: """Instantiates a new LedsPage. @param ratbag_device The ratbag device to configure, as ratbagd.RatbagdDevice """ Gtk.Box.__init__(self, *args, **kwargs) self._device = ratbagd_device self._profile = profile self._mousemap = MouseMap("#Leds", self._device, spacing=20, border_width=20) self.pack_start(self._mousemap, True, True, 0) self._sizegroup = Gtk.SizeGroup(mode=Gtk.SizeGroupMode.HORIZONTAL) for led in profile.leds: mode = _(RatbagdLed.LED_DESCRIPTION[led.mode]) button = OptionButton(mode) button.connect("clicked", self._on_button_clicked, led) connect_signal_with_weak_ref( self, led, "notify::mode", self._on_led_mode_changed, button ) self._mousemap.add(button, f"#led{led.index}") self._sizegroup.add_widget(button) self.show_all() def _on_led_mode_changed( self, led: RatbagdLed, pspec: Optional[GObject.ParamSpec], button: OptionButton ) -> None: mode = _(RatbagdLed.LED_DESCRIPTION[led.mode]) button.set_label(mode) def _on_button_clicked(self, button: OptionButton, led: RatbagdLed) -> None: # Presents the LedDialog to configure the LED corresponding to the # clicked button. dialog = LedDialog(led, transient_for=self.get_toplevel()) dialog.connect("response", self._on_dialog_response, led) dialog.present() def _on_dialog_response( self, dialog: LedDialog, response: Gtk.ResponseType, led: RatbagdLed ) -> None: # The user either pressed cancel or apply. If it's apply, apply the # changes before closing the dialog, otherwise just close the dialog. if response == Gtk.ResponseType.APPLY: led.mode = dialog.mode led.color = dialog.color led.brightness = dialog.brightness led.effect_duration = dialog.effect_duration dialog.destroy() piper-0.8/piper/mousemap.py000066400000000000000000000430201467456234500160360ustar00rootroot00000000000000# SPDX-License-Identifier: GPL-2.0-or-later from typing import Any, List, Optional, Tuple import cairo import gi import sys from lxml import etree from piper.svg import get_svg from .ratbagd import RatbagdDevice gi.require_version("Gdk", "3.0") gi.require_version("Gtk", "3.0") gi.require_version("Rsvg", "2.0") from gi.repository import Gdk, GLib, Gtk, GObject, Rsvg # noqa """This module contains the MouseMap widget (and its helper class _MouseMapChild), which is central to the button and LED configuration stack pages. The MouseMap widget draws the device SVG in the center and lays out a bunch of child widgets relative to the leaders in the device SVG.""" class _MouseMapChild: # A helper class to manage children and their properties. def __init__(self, widget: Gtk.Widget, is_left: bool, svg_id: str) -> None: self._widget = widget self._is_left = is_left self._svg_id = svg_id self._svg_leader = f"{svg_id}-leader" self._svg_path = f"{svg_id}-path" @property def widget(self) -> Gtk.Widget: # The widget belonging to this child. return self._widget @property def svg_id(self) -> str: # The identifier of the SVG element with which this child's widget is # paired. return self._svg_id @property def svg_leader(self) -> str: # The identifier of the leader SVG element with which this child's # widget is paired. return self._svg_leader @property def svg_path(self) -> str: # The identifier of the SVG element's path with which this child's # widget is paired. return self._svg_path @property def is_left(self) -> bool: # True iff this child's widget is allocated to the left of the SVG. return self._is_left class MouseMap(Gtk.Container): """A Gtk.Container subclass to draw a device SVG with child widgets that map to the SVG. The SVG should have objects with identifiers, whose value should also be given to the `add` method. See `do_size_allocate` and https://github.com/libratbag/libratbag/blob/master/data/README.md for more information. """ __gtype_name__ = "MouseMap" __gproperties__ = { "spacing": ( int, "spacing", "The amount of space between children and the SVG leaders", 0, GLib.MAXINT, 0, GObject.ParamFlags.READABLE, ), } def __init__( self, layer: str, ratbagd_device: RatbagdDevice, spacing: int = 10, *args, **kwargs, ) -> None: """Instantiates a new MouseMap. @param layer The SVG layer whose leaders to draw, according to librsvg so e.g. `#layer1`. @param ratbagd_device The device that should be mapped, as ratbagd.RatbagdDevice @param spacing The spacing to place between the SVG's leaders and the widgets, as int @raises ValueError when an argument is invalid, or when the given device has no image registered. @raises GLib.Error when the SVG cannot be loaded. """ if layer is None: raise ValueError("Layer cannot be None") if ratbagd_device is None: raise ValueError("Device cannot be None") try: svg_bytes = get_svg(ratbagd_device.model) assert svg_bytes is not None handle = Rsvg.Handle.new_from_data(svg_bytes) assert handle is not None self._handle: Rsvg.Handle = handle self._svg_data = etree.fromstring(svg_bytes) except FileNotFoundError as e: raise ValueError("Device has no image or its path is invalid") from e Gtk.Container.__init__(self, *args, **kwargs) self.set_has_window(False) self.spacing = spacing self._layer = layer self._device = ratbagd_device self._children: List[_MouseMapChild] = [] self._highlight_element: Optional[str] = None # TODO: remove this when we're out of the transition to toned down SVGs device = self._handle.has_sub("#Device") buttons = self._handle.has_sub("#Buttons") leds = self._handle.has_sub("#LEDs") if not device or not buttons or not leds: print("Device SVG is incompatible", file=sys.stderr) def add(self, widget: Gtk.Widget, svg_id: str) -> None: """Adds the given widget to the map, bound to the given SVG element identifier. If the element identifier or its leader is not found in the SVG, the widget is not added. @param widget The widget to add, as Gtk.Widget @param svg_id The identifier of the SVG element with which this widget is to be paired, as str """ svg_leader = f"{svg_id}-leader" if ( widget is None or svg_id is None or not self._handle.has_sub(svg_id) or not self._handle.has_sub(svg_leader) ): return is_left = self._xpath_has_style(svg_leader[1:], "text-align:end") child = _MouseMapChild(widget, is_left, svg_id) self._children.append(child) widget.connect("enter-notify-event", self._on_enter, child) widget.connect("leave-notify-event", self._on_leave) widget.set_parent(self) def do_remove(self, widget: Gtk.Widget) -> None: """Removes the given widget from the map. @param widget The widget to remove, as Gtk.Widget """ if widget is not None: for child in self._children: if child.widget == widget: self._children.remove(child) child.widget.unparent() break def do_forall( self, include_internals: bool, callback: "Gtk.Callback", *parameters ) -> None: """Invokes the given callback on each child, with the given parameters. @param include_internals Whether to run on internal children as well, as boolean. Ignored, as there are no internal children. @param callback The callback to call on each child, as Gtk.Callback @param parameters The parameters to pass to the callback, as object or None. """ try: if callback is not None: for child in self._children: callback(child.widget, *parameters) except AttributeError: # See https://bugzilla.gnome.org/show_bug.cgi?id=722562. pass def do_get_request_mode(self) -> Gtk.SizeRequestMode: """Gets whether the container prefers a height-for-width or a width-for-height layout. We don't want to trade width for height or height for width so we return CONSTANT_SIZE.""" return Gtk.SizeRequestMode.CONSTANT_SIZE def do_get_preferred_height(self) -> Tuple[int, int]: """Calculates the container's initial minimum and natural height. While this call is specific to width-for-height requests (that we requested not to get) we cannot be certain that our wishes are granted and hence we must implement this method as well. We just return the SVG's height plus the border widths. """ # TODO: account for children sticking out under or above the SVG, if # they exist. At the moment we cannot reliably do so because the # y-coordinates of the leaders can have any arbitrary value. For now, # we assume that the SVG is high enough to fit all children and do not # worry about setups beyond the default GNOME Adwaita. height = self._handle.props.height + 2 * self.props.border_width return height, height def do_get_preferred_width(self) -> Tuple[int, int]: """Calculates the container's initial minimum and natural width. While this call is specific to height-for-width requests (that we requested not to get) we cannot be certain that our wishes are granted and hence we must implement this method as well. We return the sum of the SVG's width, the natural child widths (left and right), spacing and border width. """ width = 2 * self.props.border_width width_svg = self._handle.props.width width_left = [ child.widget.get_preferred_width()[1] for child in self._children if child.is_left ] width_right = [ child.widget.get_preferred_width()[1] for child in self._children if not child.is_left ] width_left = max(width_left, default=0) width_right = max(width_right, default=0) width += width_left + width_svg + width_right + self.spacing if width_left > 0: width += self.spacing return width, width def do_get_preferred_height_for_width(self, width: int) -> Tuple[int, int]: """Returns this container's minimum and natural height if it would be given the specified width. While this call is specific to height-for-width requests (that we requested not to get) we cannot be certain that our wishes are granted and hence we must implement this method as well. Since we really want to be the same size always, we simply return do_get_preferred_height. @param width The given width, as int. Ignored. """ return self.do_get_preferred_height() def do_get_preferred_width_for_height(self, height: int) -> Tuple[int, int]: """Returns this container's minimum and natural width if it would be given the specified height. While this call is specific to width-for-height requests (that we requested not to get) we cannot be certain that our wishes are granted and hence we must implement this method as well. Since we really want to be the same size always, we simply return do_get_preferred_width. @param height The given height, as int. Ignored. """ return self.do_get_preferred_width() def do_size_allocate(self, allocation: Gdk.Rectangle) -> None: """Assigns a size and position to the child widgets. Children may adjust the given allocation in their adjust_size_allocation virtual method implementation. @param allocation The position and size allocated to this container, as Gdk.Rectangle """ self.set_allocation(allocation) x, y = self._translate_to_origin() child_allocation = Gdk.Rectangle() for child in self._children: if not child.widget.get_visible(): continue svg_geom = self._get_svg_sub_geometry(child.svg_leader)[1] nat_size = child.widget.get_preferred_size()[1] if child.is_left: child_allocation.x = x + svg_geom.x - self.spacing - nat_size.width else: child_allocation.x = x + svg_geom.x + self.spacing child_allocation.y = ( y + svg_geom.y + 0.5 * svg_geom.height - 0.5 * nat_size.height ) child_allocation.width = nat_size.width child_allocation.height = nat_size.height if not child.widget.get_has_window(): child_allocation.x += allocation.x child_allocation.y += allocation.y child.widget.size_allocate(child_allocation) def do_draw(self, cr: cairo.Context) -> None: """Draws the container to the given Cairo context. The top left corner of the widget will be drawn to the currently set origin point of the context. The container needs to propagate the draw signal to its children. @param cr The Cairo context to draw into, as cairo.Context """ scale_factor = self.get_scale_factor() target = cr.get_target() target.set_device_scale(scale_factor, scale_factor) cr.save() x, y = self._translate_to_origin() cr.translate(x, y) self._draw_device(cr) cr.restore() for child in self._children: self.propagate_draw(child.widget, cr) def do_get_property(self, prop: GObject.ParamSpec) -> Any: """Gets a property value. @param prop The property to get, as GObject.ParamSpec """ if prop.name == "spacing": return self.spacing raise AttributeError(f"Unknown property {prop.name}") def _on_enter( self, widget: Gtk.Widget, event: Gdk.EventCrossing, child: _MouseMapChild ) -> None: # Highlights the element in the SVG to which the given widget belongs. self._highlight_element = child.svg_id self._redraw_svg_element(child.svg_id) def _on_leave(self, widget: Gtk.Widget, event: Gdk.EventCrossing) -> None: # Restores the device SVG to its original state. old_highlight = self._highlight_element if old_highlight is None: return self._highlight_element = None self._redraw_svg_element(old_highlight) def _xpath_has_style(self, svg_id: str, style: str) -> bool: # Checks if the SVG element with the given identifier has the given # style attribute set. namespaces = { "sodipodi": "http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd", "cc": "http://web.resource.org/cc/", "svg": "http://www.w3.org/2000/svg", "dc": "http://purl.org/dc/elements/1.1/", "xlink": "http://www.w3.org/1999/xlink", "rdf": "http://www.w3.org/1999/02/22-rdf-syntax-ns#", "inkscape": "http://www.inkscape.org/namespaces/inkscape", } query = f'//svg:rect[@id="{svg_id}"][contains(@style, "{style}")]' element = self._svg_data.xpath(query, namespaces=namespaces) return element is not None and len(element) == 1 and element[0] is not None def _get_svg_sub_geometry(self, svg_id: str) -> Tuple[bool, Gdk.Rectangle]: # Helper method to get an SVG element's x- and y-coordinates, width and # height. ret = Gdk.Rectangle() ok, svg_pos = self._handle.get_position_sub(svg_id) if not ok: print( "Warning: cannot retrieve element's position:", svg_id, file=sys.stderr ) return ok, ret ret.x = svg_pos.x ret.y = svg_pos.y ok, svg_dim = self._handle.get_dimensions_sub(svg_id) if not ok: print( "Warning: cannot retrieve element's dimensions:", svg_id, file=sys.stderr, ) return ok, ret ret.width = svg_dim.width ret.height = svg_dim.height return ok, ret def _redraw_svg_element(self, svg_id: str) -> None: # Helper method to redraw an element of the SVG image. Attempts to # redraw only the element (plus an offset), but will fall back to # redrawing the complete SVG. x, y = self._translate_to_origin() ok, svg_geom = self._get_svg_sub_geometry(svg_id) if not ok: svg_width = self._handle.props.width svg_height = self._handle.props.height self.queue_draw_area(x, y, svg_width, svg_height) else: self.queue_draw_area( x + svg_geom.x - 10, y + svg_geom.y - 10, svg_geom.width + 20, svg_geom.height + 20, ) def _translate_to_origin(self) -> Tuple[int, int]: # Translates the coordinate system such that the SVG and its buttons # will be drawn in the center of the allocated space. The returned x- # and y-coordinates will be the top left corner of the centered SVG. allocation = self.get_allocation() width = self.get_preferred_width()[1] height = self.get_preferred_height()[1] width_left = [ child.widget.get_preferred_width()[1] for child in self._children if child.is_left ] width_left = max(width_left, default=0) if width_left > 0: width_left += self.spacing x = (allocation.width - width) / 2 + self.props.border_width + width_left y = (allocation.height - height) / 2 + self.props.border_width return round(x), round(y) def _draw_device(self, cr: cairo.Context) -> None: # Draws the SVG into the Cairo context. If there is an element to be # highlighted, it will do as such in a separate surface which will be # used as a mask over the device surface. style_context = self.get_style_context() style_context.save() color = style_context.get_color(Gtk.StateFlags.LINK) style_context.restore() cr.set_source_rgba(color.red, color.green, color.blue, 0.5) self._handle.render_cairo_sub(cr, id="#Device") if self._highlight_element is not None: svg_surface = cr.get_target() highlight_surface = svg_surface.create_similar( cairo.CONTENT_COLOR_ALPHA, self._handle.props.width, self._handle.props.height, ) highlight_context = cairo.Context(highlight_surface) self._handle.render_cairo_sub(highlight_context, self._highlight_element) cr.mask_surface(highlight_surface, 0, 0) for child in self._children: self._handle.render_cairo_sub(cr, id=child.svg_path) self._handle.render_cairo_sub(cr, id=child.svg_leader) piper-0.8/piper/mouseperspective.py000066400000000000000000000172741467456234500176260ustar00rootroot00000000000000# SPDX-License-Identifier: GPL-2.0-or-later from gettext import gettext as _ from typing import Optional from .buttonspage import ButtonsPage from .profilerow import ProfileRow from .ratbagd import RatbagdDevice, RatbagdProfile from .resolutionspage import ResolutionsPage from .advancedpage import AdvancedPage from .ledspage import LedsPage from .util.gobject import connect_signal_with_weak_ref import gi gi.require_version("Gtk", "3.0") from gi.repository import GLib, GObject, Gtk # noqa @Gtk.Template(resource_path="/org/freedesktop/Piper/ui/MousePerspective.ui") class MousePerspective(Gtk.Overlay): """The perspective to configure a mouse.""" __gtype_name__ = "MousePerspective" _titlebar: Gtk.HeaderBar = Gtk.Template.Child() # type: ignore add_profile_button: Gtk.Button = Gtk.Template.Child() # type: ignore button_commit: Gtk.Button = Gtk.Template.Child() # type: ignore button_profile: Gtk.Button = Gtk.Template.Child() # type: ignore label_profile: Gtk.Label = Gtk.Template.Child() # type: ignore listbox_profiles: Gtk.ListBox = Gtk.Template.Child() # type: ignore notification_error: Gtk.Revealer = Gtk.Template.Child() # type: ignore stack: Gtk.Stack = Gtk.Template.Child() # type: ignore def __init__(self, *args, **kwargs) -> None: """Instantiates a new MousePerspective.""" Gtk.Overlay.__init__(self, *args, **kwargs) self._device: Optional[RatbagdDevice] = None self._profile: Optional[RatbagdProfile] = None self._notification_error_timeout_id = 0 @GObject.Property def name(self) -> str: """The name of this perspective.""" return "mouse_perspective" @GObject.Property def titlebar(self) -> Gtk.Widget: """The titlebar to this perspective.""" return self._titlebar @GObject.Property def can_go_back(self) -> bool: """Whether this perspective wants a back button to be displayed in case there is more than one connected device.""" return True @GObject.Property def can_shutdown(self) -> bool: if self._device is None: return True """Whether this perspective can safely shutdown.""" return all(not profile.dirty for profile in self._device.profiles) @GObject.Property def device(self) -> RatbagdDevice: assert self._device is not None return self._device def set_device(self, device: RatbagdDevice) -> None: self._device = device connect_signal_with_weak_ref( self, device, "resync", lambda _: self._show_notification_error() ) connect_signal_with_weak_ref( self, self._device, "active-profile-changed", self._on_active_profile_changed, ) active_profile = device.active_profile assert active_profile is not None self._set_profile(active_profile) self.button_profile.set_visible(len(device.profiles) > 1) self.listbox_profiles.foreach(Gtk.Widget.destroy) for profile in device.profiles: connect_signal_with_weak_ref( self, profile, "notify::disabled", self._on_profile_notify_disabled ) connect_signal_with_weak_ref( self, profile, "notify::dirty", self._on_profile_notify_dirty ) row = ProfileRow(profile) self.listbox_profiles.insert(row, profile.index) self._on_profile_notify_disabled(active_profile, None) self._select_profile_row(active_profile) def _select_profile_row(self, profile: RatbagdProfile) -> None: for row in self.listbox_profiles.get_children(): if row.profile is profile: self.listbox_profiles.select_row(row) self.label_profile.set_label(row.name) break def _set_profile(self, profile: RatbagdProfile) -> None: assert self._device is not None self._select_profile_row(profile) self._profile = profile self.stack.foreach(Gtk.Widget.destroy) if profile.resolutions: self.stack.add_titled( ResolutionsPage(self._device, profile), "resolutions", _("Resolutions") ) if profile.buttons: self.stack.add_titled( ButtonsPage(self._device, profile), "buttons", _("Buttons") ) if profile.leds: self.stack.add_titled(LedsPage(self._device, profile), "leds", _("LEDs")) # TODO: get rid of this duplicated logic. are_report_rates_supported = ( profile.report_rate != 0 and len(profile.report_rates) != 0 ) if ( profile.angle_snapping != -1 or profile.debounces or are_report_rates_supported ): self.stack.add_titled( AdvancedPage(self._device, profile), "advanced", _("Advanced") ) self._on_profile_notify_dirty(profile, None) def _hide_notification_error(self) -> None: if self._notification_error_timeout_id != 0: GLib.Source.remove(self._notification_error_timeout_id) self._notification_error_timeout_id = 0 self.notification_error.set_reveal_child(False) def _show_notification_error(self) -> None: self.notification_error.set_reveal_child(True) self._notification_error_timeout_id = GLib.timeout_add_seconds( 5, self._on_notification_error_timeout ) def _on_active_profile_changed( self, _device: RatbagdDevice, profile: RatbagdProfile ) -> None: # TODO: preserve the active tab. self._set_profile(profile) def _on_notification_error_timeout(self) -> bool: self._hide_notification_error() return False @Gtk.Template.Callback("_on_save_button_clicked") def _on_save_button_clicked(self, _button: Gtk.Button) -> None: assert self._device is not None self._device.commit() @Gtk.Template.Callback("_on_notification_error_close_clicked") def _on_notification_error_close_clicked(self, button: Gtk.Button) -> None: self._hide_notification_error() @Gtk.Template.Callback("_on_profile_row_activated") def _on_profile_row_activated(self, listbox: Gtk.ListBox, row: ProfileRow) -> None: row.set_active() @Gtk.Template.Callback("_on_add_profile_button_clicked") def _on_add_profile_button_clicked(self, button: Gtk.Button) -> None: assert self._device is not None # Enable the first disabled profile we find. for profile in self._device.profiles: if not profile.disabled: continue profile.disabled = False break def _on_profile_notify_disabled( self, profile: RatbagdProfile, pspec: Optional[GObject.ParamSpec] ) -> None: assert self._device is not None self.add_profile_button.set_sensitive( any(p.disabled for p in self._device.profiles) ) def _on_profile_notify_dirty( self, profile: RatbagdProfile, pspec: Optional[GObject.ParamSpec] ) -> None: assert self._device is not None device_dirty = any(p.dirty for p in self._device.profiles) style_context = self.button_commit.get_style_context() if device_dirty: style_context.add_class("suggested-action") self.button_commit.set_sensitive(True) else: # There is no way to make a single profile non-dirty, so this works # for now. Ideally, this should however check if there are any other # profiles on the device that are dirty. style_context.remove_class("suggested-action") self.button_commit.set_sensitive(False) piper-0.8/piper/optionbutton.py000066400000000000000000000016231467456234500167570ustar00rootroot00000000000000# SPDX-License-Identifier: GPL-2.0-or-later from typing import Optional import gi gi.require_version("Gtk", "3.0") from gi.repository import Gtk # noqa @Gtk.Template(resource_path="/org/freedesktop/Piper/ui/OptionButton.ui") class OptionButton(Gtk.Button): """A Gtk.Button subclass that displays a label, a separator and a cog.""" __gtype_name__ = "OptionButton" label: Gtk.Label = Gtk.Template.Child() # type: ignore def __init__(self, label: Optional[str] = None, *args, **kwargs) -> None: """Instantiates a new OptionButton. @param label The text to display. """ Gtk.Button.__init__(self, *args, **kwargs) if label is not None: self.set_label(label) def set_label(self, label: str) -> None: """Set the text to display. @param label The new text to display, as str. """ self.label.set_text(label) piper-0.8/piper/profilerow.py000066400000000000000000000035601467456234500164050ustar00rootroot00000000000000# SPDX-License-Identifier: GPL-2.0-or-later import sys from typing import Optional import gi from piper.ratbagd import RatbagdProfile from .util.gobject import connect_signal_with_weak_ref gi.require_version("Gtk", "3.0") from gi.repository import GObject, Gtk # noqa @Gtk.Template(resource_path="/org/freedesktop/Piper/ui/ProfileRow.ui") class ProfileRow(Gtk.ListBoxRow): """A Gtk.ListBoxRow subclass containing the widgets to display a profile in the profile poper.""" __gtype_name__ = "ProfileRow" title: Gtk.Label = Gtk.Template.Child() # type: ignore def __init__(self, profile: RatbagdProfile, *args, **kwargs) -> None: Gtk.ListBoxRow.__init__(self, *args, **kwargs) self._profile = profile connect_signal_with_weak_ref( self, self._profile, "notify::disabled", self._on_profile_notify_disabled ) name = profile.name if not name: name = f"Profile {profile.index}" self.title.set_text(name) self.show_all() self.set_visible(not profile.disabled) def _on_profile_notify_disabled( self, profile: RatbagdProfile, pspec: Optional[GObject.ParamSpec] ) -> None: self.set_visible(not profile.disabled) @Gtk.Template.Callback("_on_delete_button_clicked") def _on_delete_button_clicked(self, button: Gtk.Button) -> None: if not self._profile.is_active: self._profile.disabled = True else: # TODO: display this in the app print("Trying to disable the active profile", file=sys.stderr) def set_active(self) -> None: """Activates the profile paired with this row.""" self._profile.set_active() @GObject.Property def name(self) -> str: return self.title.get_text() @GObject.Property def profile(self) -> RatbagdProfile: return self._profile piper-0.8/piper/ratbagd.py000066400000000000000000001210661467456234500156230ustar00rootroot00000000000000# Copyright 2016-2019 Red Hat, Inc. # # Permission is hereby granted, free of charge, to any person obtaining a # copy of this software and associated documentation files (the "Software"), # to deal in the Software without restriction, including without limitation # the rights to use, copy, modify, merge, publish, distribute, sublicense, # and/or sell copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice (including the next # paragraph) shall be included in all copies or substantial portions of the # Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER # DEALINGS IN THE SOFTWARE. import os import sys import hashlib from enum import IntEnum from evdev import ecodes from gettext import gettext as _ from gi.repository import Gio, GLib, GObject from typing import List, Optional, Tuple, Union # Deferred translations, see https://docs.python.org/3/library/gettext.html#deferred-translations def N_(x): return x def evcode_to_str(evcode: int) -> str: # Values in ecodes.keys are stored as either a str or list[str]. value = ecodes.keys[evcode] if isinstance(value, list): return value[0] return value class RatbagErrorCode(IntEnum): SUCCESS = 0 """An error occurred on the device. Either the device is not a libratbag device or communication with the device failed.""" DEVICE = -1000 """Insufficient capabilities. This error occurs when a requested change is beyond the device's capabilities.""" CAPABILITY = -1001 """Invalid value or value range. The provided value or value range is outside of the legal or supported range.""" VALUE = -1002 """A low-level system error has occurred, e.g. a failure to access files that should be there. This error is usually unrecoverable and libratbag will print a log message with details about the error.""" SYSTEM = -1003 """Implementation bug, either in libratbag or in the caller. This error is usually unrecoverable and libratbag will print a log message with details about the error.""" IMPLEMENTATION = -1004 class RatbagDeviceType(IntEnum): """DeviceType property specified in the .device files""" """There was no DeviceType specified for this device""" UNSPECIFIED = 0 """Device is specified as anything other than a mouse or a keyboard""" OTHER = 1 """Device is specified as a mouse""" MOUSE = 2 """Device is specified as a keyboard""" KEYBOARD = 3 class RatbagdIncompatibleError(Exception): """ratbagd is incompatible with this client""" def __init__(self, ratbagd_version, required_version): super().__init__() self.ratbagd_version = ratbagd_version self.required_version = required_version self.message = f"ratbagd API version is {ratbagd_version} but we require {required_version}" def __str__(self): return self.message class RatbagdUnavailableError(Exception): """Signals DBus is unavailable or the ratbagd daemon is not available.""" class RatbagdDBusTimeoutError(Exception): """Signals that a timeout occurred during a DBus method call.""" class RatbagError(Exception): """A common base exception to catch any ratbag exception.""" class RatbagDeviceError(RatbagError): """An exception corresponding to RatbagErrorCode.DEVICE.""" class RatbagCapabilityError(RatbagError): """An exception corresponding to RatbagErrorCode.CAPABILITY.""" class RatbagValueError(RatbagError): """An exception corresponding to RatbagErrorCode.VALUE.""" class RatbagSystemError(RatbagError): """An exception corresponding to RatbagErrorCode.SYSTEM.""" class RatbagImplementationError(RatbagError): """An exception corresponding to RatbagErrorCode.IMPLEMENTATION.""" """A table mapping RatbagErrorCode values to RatbagError* exceptions.""" EXCEPTION_TABLE = { RatbagErrorCode.DEVICE: RatbagDeviceError, RatbagErrorCode.CAPABILITY: RatbagCapabilityError, RatbagErrorCode.VALUE: RatbagValueError, RatbagErrorCode.SYSTEM: RatbagSystemError, RatbagErrorCode.IMPLEMENTATION: RatbagImplementationError, } class _RatbagdDBus(GObject.GObject): _dbus = None def __init__(self, interface, object_path): super().__init__() if _RatbagdDBus._dbus is None: try: _RatbagdDBus._dbus = Gio.bus_get_sync(Gio.BusType.SYSTEM, None) except GLib.Error as e: raise RatbagdUnavailableError(e.message) from e ratbag1 = "org.freedesktop.ratbag1" if os.environ.get("RATBAG_TEST"): ratbag1 = "org.freedesktop.ratbag_devel1" if object_path is None: object_path = "/" + ratbag1.replace(".", "/") self._object_path = object_path self._interface = f"{ratbag1}.{interface}" try: self._proxy = Gio.DBusProxy.new_sync( _RatbagdDBus._dbus, Gio.DBusProxyFlags.NONE, None, ratbag1, object_path, self._interface, None, ) except GLib.Error as e: raise RatbagdUnavailableError(e.message) from e if self._proxy.get_name_owner() is None: raise RatbagdUnavailableError(f"No one currently owns {ratbag1}") self._proxy.connect("g-properties-changed", self._on_properties_changed) self._proxy.connect("g-signal", self._on_signal_received) def _on_properties_changed(self, proxy, changed_props, invalidated_props): # Implement this in derived classes to respond to property changes. pass def _on_signal_received(self, proxy, sender_name, signal_name, parameters): # Implement this in derived classes to respond to signals. pass def _find_object_with_path(self, iterable, object_path): # Find the index of an object in an iterable that whose object path # matches the given object path. for index, obj in enumerate(iterable): if obj._object_path == object_path: return index return -1 def _get_dbus_property(self, property): # Retrieves a cached property from the bus, or None. p = self._proxy.get_cached_property(property) if p is not None: return p.unpack() return p def _get_dbus_property_nonnull(self, property: str): p = self._get_dbus_property(property) if p is None: raise ValueError(f"D-Bus API returned `None` for property {property}") return p def _set_dbus_property(self, property, type, value, readwrite=True): # Sets a cached property on the bus. # Take our real value and wrap it into a variant. To call # org.freedesktop.DBus.Properties.Set we need to wrap that again # into a (ssv), where v is our value's variant. # args to .Set are "interface name", "function name", value-variant val = GLib.Variant(f"{type}", value) if readwrite: pval = GLib.Variant("(ssv)", (self._interface, property, val)) self._proxy.call_sync( "org.freedesktop.DBus.Properties.Set", pval, Gio.DBusCallFlags.NO_AUTO_START, 2000, None, ) # This is our local copy, so we don't have to wait for the async # update self._proxy.set_cached_property(property, val) def _dbus_call(self, method, type, *value): # Calls a method synchronously on the bus, using the given method name, # type signature and values. # # If the result is valid, it is returned. Invalid results raise the # appropriate RatbagError* or RatbagdDBus* exception, or GLib.Error if # it is an unexpected exception that probably shouldn't be passed up to # the UI. val = GLib.Variant(f"({type})", value) try: res = self._proxy.call_sync( method, val, Gio.DBusCallFlags.NO_AUTO_START, 2000, None ) if res in EXCEPTION_TABLE: raise EXCEPTION_TABLE[res] return res.unpack()[0] # Result is always a tuple except GLib.Error as e: if e.code == Gio.IOErrorEnum.TIMED_OUT: raise RatbagdDBusTimeoutError(e.message) from e # Unrecognized error code. print(e.message, file=sys.stderr) raise def __eq__(self, other): return other and self._object_path == other._object_path class Ratbagd(_RatbagdDBus): """The ratbagd top-level object. Provides a list of devices available through ratbagd; actual interaction with the devices is via the RatbagdDevice, RatbagdProfile, RatbagdResolution and RatbagdButton objects. Throws RatbagdUnavailableError when the DBus service is not available. """ __gsignals__ = { "device-added": (GObject.SignalFlags.RUN_FIRST, None, (GObject.TYPE_PYOBJECT,)), "device-removed": ( GObject.SignalFlags.RUN_FIRST, None, (GObject.TYPE_PYOBJECT,), ), "daemon-disappeared": (GObject.SignalFlags.RUN_FIRST, None, ()), } def __init__(self, api_version): super().__init__("Manager", None) result = self._get_dbus_property("Devices") if result is None and not self._proxy.get_cached_property_names(): raise RatbagdUnavailableError( "Make sure it is running and your user is in the required groups." ) if self.api_version != api_version: raise RatbagdIncompatibleError(self.api_version or -1, api_version) self._devices = [RatbagdDevice(objpath) for objpath in result or []] self._proxy.connect("notify::g-name-owner", self._on_name_owner_changed) def _on_name_owner_changed(self, *kwargs): self.emit("daemon-disappeared") def _on_properties_changed(self, proxy, changed_props, invalidated_props): try: new_device_object_paths = changed_props["Devices"] except KeyError: # Different property changed, skip. pass else: object_paths = [d._object_path for d in self._devices] for object_path in new_device_object_paths: if object_path not in object_paths: device = RatbagdDevice(object_path) self._devices.append(device) self.emit("device-added", device) for device in self.devices: if device._object_path not in new_device_object_paths: self._devices.remove(device) self.emit("device-removed", device) self.notify("devices") @GObject.Property def api_version(self): return self._get_dbus_property("APIVersion") @GObject.Property def devices(self): """A list of RatbagdDevice objects supported by ratbagd.""" return self._devices def __getitem__(self, id): """Returns the requested device, or None.""" for d in self.devices: if d.id == id: return d return None def __enter__(self): return self def __exit__(self, exc_type, exc_val, exc_tb): pass class RatbagdDevice(_RatbagdDBus): """Represents a ratbagd device.""" __gsignals__ = { "active-profile-changed": ( GObject.SignalFlags.RUN_FIRST, None, (GObject.TYPE_PYOBJECT,), ), "resync": (GObject.SignalFlags.RUN_FIRST, None, ()), } def __init__(self, object_path): super().__init__("Device", object_path) # FIXME: if we start adding and removing objects from this list, # things will break! result = self._get_dbus_property("Profiles") or [] self._profiles = [RatbagdProfile(objpath) for objpath in result] for profile in self._profiles: profile.connect("notify::is-active", self._on_active_profile_changed) # Use a SHA1 of our object path as our device's ID self._id = hashlib.sha1(object_path.encode("utf-8")).hexdigest() def _on_signal_received(self, proxy, sender_name, signal_name, parameters): if signal_name == "Resync": self.emit("resync") def _on_active_profile_changed(self, profile, pspec): if profile.is_active: self.emit("active-profile-changed", self._profiles[profile.index]) @GObject.Property def id(self): return self._id @id.setter def id(self, id): self._id = id @GObject.Property def model(self): """The unique identifier for this device model.""" return self._get_dbus_property("Model") @GObject.Property def name(self): """The device name, usually provided by the kernel.""" return self._get_dbus_property("Name") @GObject.Property def device_type(self): """The device type, see RatbagDeviceType""" return RatbagDeviceType(self._get_dbus_property("DeviceType")) @GObject.Property def firmware_version(self): """The firmware version of the device.""" return self._get_dbus_property("FirmwareVersion") @GObject.Property def profiles(self): """A list of RatbagdProfile objects provided by this device.""" return self._profiles @GObject.Property def active_profile(self): """The currently active profile. This is a non-DBus property computed over the cached list of profiles. In the unlikely case that your device driver is misconfigured and there is no active profile, this returns `None`.""" for profile in self._profiles: if profile.is_active: return profile print( "No active profile. Please report this bug to the libratbag developers", file=sys.stderr, ) return None def commit(self): """Commits all changes made to the device. This is implemented asynchronously inside ratbagd. Hence, we just call this method and always succeed. Any failure is handled inside ratbagd by emitting the Resync signal, which automatically resynchronizes the device. No further interaction is required by the client. """ self._dbus_call("Commit", "") class RatbagdProfile(_RatbagdDBus): """Represents a ratbagd profile.""" CAP_WRITABLE_NAME = 100 CAP_SET_DEFAULT = 101 CAP_DISABLE = 102 CAP_WRITE_ONLY = 103 def __init__(self, object_path): super().__init__("Profile", object_path) self._active = self._get_dbus_property("IsActive") self._angle_snapping = self._get_dbus_property("AngleSnapping") self._debounce = self._get_dbus_property("Debounce") self._dirty = self._get_dbus_property("IsDirty") self._disabled = self._get_dbus_property("Disabled") self._report_rate = self._get_dbus_property("ReportRate") # FIXME: if we start adding and removing objects from any of these # lists, things will break! result = self._get_dbus_property("Resolutions") or [] self._resolutions = [RatbagdResolution(objpath) for objpath in result] self._subscribe_dirty(self._resolutions) result = self._get_dbus_property("Buttons") or [] self._buttons = [RatbagdButton(objpath) for objpath in result] self._subscribe_dirty(self._buttons) result = self._get_dbus_property("Leds") or [] self._leds = [RatbagdLed(objpath) for objpath in result] self._subscribe_dirty(self._leds) def _subscribe_dirty(self, objects: List[GObject.GObject]): for obj in objects: obj.connect("notify", self._on_obj_notify) def _on_obj_notify(self, obj: GObject.GObject, pspec: Optional[GObject.ParamSpec]): if not self._dirty: self._dirty = True self.notify("dirty") def _on_properties_changed(self, proxy, changed_props, invalidated_props): try: angle_snapping = changed_props["AngleSnapping"] except KeyError: # Different property changed, skip. pass else: if angle_snapping != self._angle_snapping: self._angle_snapping = angle_snapping self.notify("angle-snapping") try: debounce = changed_props["Debounce"] except KeyError: # Different property changed, skip. pass else: if debounce != self._debounce: self._debounce = debounce self.notify("debounce") try: disabled = changed_props["Disabled"] except KeyError: # Different property changed, skip. pass else: if disabled != self._disabled: self._disabled = disabled self.notify("disabled") try: active = changed_props["IsActive"] except KeyError: # Different property changed, skip. pass else: if active != self._active: self._active = active self.notify("is-active") try: dirty = changed_props["IsDirty"] except KeyError: # Different property changed, skip. pass else: if dirty != self._dirty: self._dirty = dirty self.notify("dirty") try: report_rate = changed_props["ReportRate"] except KeyError: # Different property changed, skip. pass else: if report_rate != self._report_rate: self._report_rate = report_rate self.notify("report-rate") @GObject.Property def capabilities(self): """The capabilities of this profile as an array. Capabilities not present on the profile are not in the list. Thus use e.g. if RatbagdProfile.CAP_WRITABLE_NAME in profile.capabilities: do something """ return self._get_dbus_property("Capabilities") or [] @GObject.Property def name(self): """The name of the profile""" return self._get_dbus_property("Name") @name.setter def name(self, name): """Set the name of this profile. @param name The new name, as str""" self._set_dbus_property("Name", "s", name) @GObject.Property def index(self): """The index of this profile.""" return self._get_dbus_property("Index") @GObject.Property def dirty(self): """Whether this profile is dirty.""" return self._dirty @GObject.Property def disabled(self): """tells if the profile is disabled.""" return self._disabled @disabled.setter def disabled(self, disabled): """Enable/Disable this profile. @param disabled The new state, as boolean""" self._set_dbus_property("Disabled", "b", disabled) @GObject.Property def report_rate(self) -> int: """The report rate in Hz.""" return self._report_rate @report_rate.setter def report_rate(self, rate): """Set the report rate in Hz. @param rate The new report rate, as int """ self._set_dbus_property("ReportRate", "u", rate) @GObject.Property def report_rates(self): """The list of supported report rates""" return self._get_dbus_property("ReportRates") or [] @GObject.Property def angle_snapping(self): """The angle snapping option.""" return self._angle_snapping @angle_snapping.setter def angle_snapping(self, value): """Set the angle snapping option. @param value The angle snapping option as int """ self._set_dbus_property("AngleSnapping", "i", value) @GObject.Property def debounce(self): """The button debounce time in ms.""" return self._debounce @debounce.setter def debounce(self, value): """Set the button debounce time in ms. @param value The button debounce time, as int """ self._set_dbus_property("Debounce", "i", value) @GObject.Property def debounces(self): """The list of supported debounce times""" return self._get_dbus_property("Debounces") or [] @GObject.Property def resolutions(self): """A list of RatbagdResolution objects with this profile's resolutions. Note that the list of resolutions differs between profiles but the number of resolutions is identical across profiles.""" return self._resolutions @GObject.Property def active_resolution(self): """The currently active resolution of this profile. This is a non-DBus property computed over the cached list of resolutions. In the unlikely case that your device driver is misconfigured and there is no active resolution, this returns `None`.""" for resolution in self._resolutions: if resolution.is_active: return resolution print( "No active resolution. Please report this bug to the libratbag developers", file=sys.stderr, ) return None @GObject.Property def buttons(self): """A list of RatbagdButton objects with this profile's button mappings. Note that the list of buttons differs between profiles but the number of buttons is identical across profiles.""" return self._buttons @GObject.Property def leds(self): """A list of RatbagdLed objects with this profile's leds. Note that the list of leds differs between profiles but the number of leds is identical across profiles.""" return self._leds @GObject.Property def is_active(self): """Returns True if the profile is currently active, false otherwise.""" return self._active def set_active(self): """Set this profile to be the active profile.""" ret = self._dbus_call("SetActive", "") self._set_dbus_property("IsActive", "b", True, readwrite=False) return ret class RatbagdResolution(_RatbagdDBus): """Represents a ratbagd resolution.""" CAP_SEPARATE_XY_RESOLUTION = 1 CAP_DISABLE = 2 def __init__(self, object_path): super().__init__("Resolution", object_path) self._active = self._get_dbus_property("IsActive") self._default = self._get_dbus_property("IsDefault") self._disabled = self._get_dbus_property("IsDisabled") self._resolution = self._convert_resolution_from_dbus( self._get_dbus_property_nonnull("Resolution") ) def _on_properties_changed(self, proxy, changed_props, invalidated_props): try: resolution = self._convert_resolution_from_dbus(changed_props["Resolution"]) except KeyError: # Different property changed, skip. pass else: if resolution != self._resolution: self._resolution = resolution self.notify("resolution") try: active = changed_props["IsActive"] except KeyError: # Different property changed, skip. pass else: if active != self._active: self._active = active self.notify("is-active") try: default = changed_props["IsDefault"] except KeyError: # Different property changed, skip. pass else: if default != self._default: self._default = default self.notify("is-default") try: disabled = changed_props["IsDisabled"] except KeyError: # Different property changed, skip. pass else: if disabled != self._disabled: self._disabled = disabled self.notify("is-disabled") @GObject.Property def capabilities(self): """The capabilities of this resolution as an array. Capabilities not present on the resolution are not in the list. Thus use e.g. if resolution.CAP_DISABLE in resolution.capabilities: do something """ return self._get_dbus_property("Capabilities") or [] @GObject.Property def index(self): """The index of this resolution.""" return self._get_dbus_property("Index") @staticmethod def _convert_resolution_from_dbus( res: Union[int, Tuple[int, int]] ) -> Union[Tuple[int], Tuple[int, int]]: """ Convert resolution from what D-Bus API retuns - either an int or a tuple of two ints, to a tuple of either one or two ints. """ if isinstance(res, int): return (res,) return res @GObject.Property def resolution(self): """The resolution in DPI, either as single value tuple ``(res, )`` or as tuple ``(xres, yres)``. """ return self._resolution @resolution.setter def resolution(self, resolution): """Set the x- and y-resolution using the given (xres, yres) tuple. @param res The new resolution, as (int, int) """ res = self.resolution if len(res) != len(resolution) or len(res) > 2: raise ValueError("invalid resolution precision") if len(res) == 1: variant = GLib.Variant("u", resolution[0]) else: variant = GLib.Variant("(uu)", resolution) self._set_dbus_property("Resolution", "v", variant) @GObject.Property def resolutions(self): """The list of supported DPI values""" return self._get_dbus_property("Resolutions") or [] @GObject.Property def is_active(self): """True if this is the currently active resolution, False otherwise""" return self._active @GObject.Property def is_default(self): """True if this is the currently default resolution, False otherwise""" return self._default @GObject.Property def is_disabled(self): """True if this is currently disabled, False otherwise""" return self._disabled def set_active(self): """Set this resolution to be the active one.""" ret = self._dbus_call("SetActive", "") self._set_dbus_property("IsActive", "b", True, readwrite=False) return ret def set_default(self): """Set this resolution to be the default.""" ret = self._dbus_call("SetDefault", "") self._set_dbus_property("IsDefault", "b", True, readwrite=False) return ret def set_disabled(self, disable): """Set this resolution to be disabled.""" return self._set_dbus_property("IsDisabled", "b", disable) class RatbagdButton(_RatbagdDBus): """Represents a ratbagd button.""" class ActionType(IntEnum): NONE = 0 BUTTON = 1 SPECIAL = 2 KEY = 3 MACRO = 4 class ActionSpecial(IntEnum): INVALID = -1 UNKNOWN = 1 << 30 DOUBLECLICK = (1 << 30) + 1 WHEEL_LEFT = (1 << 30) + 2 WHEEL_RIGHT = (1 << 30) + 3 WHEEL_UP = (1 << 30) + 4 WHEEL_DOWN = (1 << 30) + 5 RATCHET_MODE_SWITCH = (1 << 30) + 6 RESOLUTION_CYCLE_UP = (1 << 30) + 7 RESOLUTION_CYCLE_DOWN = (1 << 30) + 8 RESOLUTION_UP = (1 << 30) + 9 RESOLUTION_DOWN = (1 << 30) + 10 RESOLUTION_ALTERNATE = (1 << 30) + 11 RESOLUTION_DEFAULT = (1 << 30) + 12 PROFILE_CYCLE_UP = (1 << 30) + 13 PROFILE_CYCLE_DOWN = (1 << 30) + 14 PROFILE_UP = (1 << 30) + 15 PROFILE_DOWN = (1 << 30) + 16 SECOND_MODE = (1 << 30) + 17 BATTERY_LEVEL = (1 << 30) + 18 class Macro(IntEnum): NONE = 0 KEY_PRESS = 1 KEY_RELEASE = 2 WAIT = 3 """A table mapping a button's index to its usual function as defined by X and the common desktop environments.""" BUTTON_DESCRIPTION = { 0: N_("Left mouse button click"), 1: N_("Right mouse button click"), 2: N_("Middle mouse button click"), 3: N_("Backward"), 4: N_("Forward"), } """A table mapping a special function to its human-readable description.""" SPECIAL_DESCRIPTION = { ActionSpecial.INVALID: N_("Invalid"), ActionSpecial.UNKNOWN: N_("Unknown"), ActionSpecial.DOUBLECLICK: N_("Doubleclick"), ActionSpecial.WHEEL_LEFT: N_("Wheel Left"), ActionSpecial.WHEEL_RIGHT: N_("Wheel Right"), ActionSpecial.WHEEL_UP: N_("Wheel Up"), ActionSpecial.WHEEL_DOWN: N_("Wheel Down"), ActionSpecial.RATCHET_MODE_SWITCH: N_("Ratchet Mode"), ActionSpecial.RESOLUTION_CYCLE_UP: N_("Cycle Resolution Up"), ActionSpecial.RESOLUTION_CYCLE_DOWN: N_("Cycle Resolution Down"), ActionSpecial.RESOLUTION_UP: N_("Resolution Up"), ActionSpecial.RESOLUTION_DOWN: N_("Resolution Down"), ActionSpecial.RESOLUTION_ALTERNATE: N_("Resolution Switch"), ActionSpecial.RESOLUTION_DEFAULT: N_("Default Resolution"), ActionSpecial.PROFILE_CYCLE_UP: N_("Cycle Profile Up"), ActionSpecial.PROFILE_CYCLE_DOWN: N_("Cycle Profile Down"), ActionSpecial.PROFILE_UP: N_("Profile Up"), ActionSpecial.PROFILE_DOWN: N_("Profile Down"), ActionSpecial.SECOND_MODE: N_("Second Mode"), ActionSpecial.BATTERY_LEVEL: N_("Battery Level"), } def __init__(self, object_path): super().__init__("Button", object_path) def _on_properties_changed(self, proxy, changed_props, invalidated_props): if "Mapping" in changed_props.keys(): self.notify("action-type") def _mapping(self): return self._get_dbus_property("Mapping") @GObject.Property def index(self): """The index of this button.""" return self._get_dbus_property("Index") @GObject.Property def mapping(self): """An integer of the current button mapping, if mapping to a button or None otherwise.""" type, button = self._mapping() if type != RatbagdButton.ActionType.BUTTON: return None return button @mapping.setter def mapping(self, button): """Set the button mapping to the given button. @param button The button to map to, as int """ button = GLib.Variant("u", button) self._set_dbus_property( "Mapping", "(uv)", (RatbagdButton.ActionType.BUTTON, button) ) @GObject.Property def macro(self): """A RatbagdMacro object representing the currently set macro or None otherwise.""" type, macro = self._mapping() if type != RatbagdButton.ActionType.MACRO: return None return RatbagdMacro.from_ratbag(macro) @macro.setter def macro(self, macro): """Set the macro to the macro represented by the given RatbagdMacro object. @param macro A RatbagdMacro object representing the macro to apply to the button, as RatbagdMacro. """ macro = GLib.Variant("a(uu)", macro.keys) self._set_dbus_property( "Mapping", "(uv)", (RatbagdButton.ActionType.MACRO, macro) ) @GObject.Property def special(self): """An enum describing the current special mapping, if mapped to special or None otherwise.""" type, special = self._mapping() if type != RatbagdButton.ActionType.SPECIAL: return None return special @special.setter def special(self, special): """Set the button mapping to the given special entry. @param special The special entry, as one of RatbagdButton.ActionSpecial """ special = GLib.Variant("u", special) self._set_dbus_property( "Mapping", "(uv)", (RatbagdButton.ActionType.SPECIAL, special) ) @GObject.Property def key(self): type, key = self._mapping() if type != RatbagdButton.ActionType.KEY: return None return key @key.setter def key(self, key): key = GLib.Variant("u", key) self._set_dbus_property("Mapping", "(uv)", (RatbagdButton.ActionType.KEY, key)) @GObject.Property def action_type(self): """An enum describing the action type of the button. One of ActionType.NONE, ActionType.BUTTON, ActionType.SPECIAL, ActionType.MACRO. This decides which *Mapping property has a value. """ type, mapping = self._mapping() return type @GObject.Property def action_types(self): """An array of possible values for ActionType.""" return self._get_dbus_property("ActionTypes") @GObject.Property def disabled(self): type, unused = self._mapping() return type == RatbagdButton.ActionType.NONE def disable(self): """Disables this button.""" zero = GLib.Variant("u", 0) self._set_dbus_property( "Mapping", "(uv)", (RatbagdButton.ActionType.NONE, zero) ) class RatbagdMacro(GObject.Object): """Represents a button macro. Note that it uses keycodes as defined by linux/input.h and not those used by X.Org or any other higher layer such as Gdk.""" # Both a key press and release. _MACRO_KEY = 1000 _MACRO_DESCRIPTION = { RatbagdButton.Macro.KEY_PRESS: lambda key: f"↓{evcode_to_str(key)}", RatbagdButton.Macro.KEY_RELEASE: lambda key: f"↑{evcode_to_str(key)}", RatbagdButton.Macro.WAIT: lambda val: f"{val}ms", _MACRO_KEY: lambda key: f"↕{evcode_to_str(key)}", } __gsignals__ = { "macro-set": (GObject.SignalFlags.RUN_FIRST, None, ()), } def __init__(self, **kwargs): super().__init__(**kwargs) self._macro = [] def __str__(self): if not self._macro: # Translators: this is used when there is no macro to preview. return _("None") keys = [] idx = 0 while idx < len(self._macro): t, v = self._macro[idx] try: if t == RatbagdButton.Macro.KEY_PRESS: # Check for a paired press/release event t2, v2 = self._macro[idx + 1] if t2 == RatbagdButton.Macro.KEY_RELEASE and v == v2: t = self._MACRO_KEY idx += 1 except IndexError: pass keys.append(self._MACRO_DESCRIPTION[t](v)) idx += 1 return " ".join(keys) @GObject.Property def keys(self): """A list of (RatbagdButton.Macro.*, value) tuples representing the current macro.""" return self._macro @staticmethod def from_ratbag(macro): """Instantiates a new RatbagdMacro instance from the given macro in libratbag format. @param macro The macro in libratbag format, as [(RatbagdButton.Macro.*, value)]. """ ratbagd_macro = RatbagdMacro() # Do not emit notify::keys for every key that we add. with ratbagd_macro.freeze_notify(): for type, value in macro: ratbagd_macro.append(type, value) return ratbagd_macro def accept(self): """Applies the currently cached macro.""" self.emit("macro-set") def append(self, type, value): """Appends the given event to the current macro. @param type The type of event, as one of RatbagdButton.Macro.*. @param value If the type denotes a key event, the X.Org or Gdk keycode of the event, as int. Otherwise, the value of the timeout in milliseconds, as int. """ # Only append if the entry isn't identical to the last one, as we cannot # e.g. have two identical key presses in a row. if len(self._macro) == 0 or (type, value) != self._macro[-1]: self._macro.append((type, value)) self.notify("keys") class RatbagdLed(_RatbagdDBus): """Represents a ratbagd led.""" class Mode(IntEnum): OFF = 0 ON = 1 CYCLE = 2 BREATHING = 3 class ColorDepth(IntEnum): MONOCHROME = 0 RGB_888 = 1 RGB_111 = 2 LED_DESCRIPTION = { # Translators: the LED is off. Mode.OFF: N_("Off"), # Translators: the LED has a single, solid color. Mode.ON: N_("Solid"), # Translators: the LED is cycling between red, green and blue. Mode.CYCLE: N_("Cycle"), # Translators: the LED's is pulsating a single color on different # brightnesses. Mode.BREATHING: N_("Breathing"), } def __init__(self, object_path): super().__init__("Led", object_path) self._brightness = self._get_dbus_property("Brightness") self._color = self._get_dbus_property("Color") self._effect_duration = self._get_dbus_property("EffectDuration") self._mode: RatbagdLed.Mode = self._get_dbus_property_nonnull("Mode") @GObject.Property def index(self): """The index of this led.""" return self._get_dbus_property("Index") @GObject.Property def mode(self): """This led's mode, one of Mode.OFF, Mode.ON, Mode.CYCLE and Mode.BREATHING.""" return self._mode @mode.setter def mode(self, mode): """Set the led's mode to the given mode. @param mode The new mode, as one of Mode.OFF, Mode.ON, Mode.CYCLE and Mode.BREATHING. """ self._set_dbus_property("Mode", "u", mode) @GObject.Property def modes(self): """The supported modes as a list""" return self._get_dbus_property("Modes") @GObject.Property def color(self): """An integer triple of the current LED color.""" return self._color @color.setter def color(self, color): """Set the led color to the given color. @param color An RGB color, as an integer triplet with values 0-255. """ self._set_dbus_property("Color", "(uuu)", color) @GObject.Property def colordepth(self): """An enum describing this led's colordepth, one of RatbagdLed.ColorDepth.MONOCHROME, RatbagdLed.ColorDepth.RGB""" return self._get_dbus_property("ColorDepth") @GObject.Property def effect_duration(self): """The LED's effect duration in ms, values range from 0 to 10000.""" return self._effect_duration @effect_duration.setter def effect_duration(self, effect_duration): """Set the effect duration in ms. Allowed values range from 0 to 10000. @param effect_duration The new effect duration, as int """ self._set_dbus_property("EffectDuration", "u", effect_duration) @GObject.Property def brightness(self): """The LED's brightness, values range from 0 to 255.""" return self._brightness @brightness.setter def brightness(self, brightness): """Set the brightness. Allowed values range from 0 to 255. @param brightness The new brightness, as int """ self._set_dbus_property("Brightness", "u", brightness) def _on_properties_changed(self, proxy, changed_props, invalidated_props): try: brightness = changed_props["Brightness"] except KeyError: # Different property changed, skip. pass else: if brightness != self._brightness: self._brightness = brightness self.notify("brightness") try: color = changed_props["Color"] except KeyError: # Different property changed, skip. pass else: if color != self._color: self._color = color self.notify("color") try: effect_duration = changed_props["EffectDuration"] except KeyError: # Different property changed, skip. pass else: if effect_duration != self._effect_duration: self._effect_duration = effect_duration self.notify("effect-duration") try: mode = changed_props["Mode"] except KeyError: # Different property changed, skip. pass else: if mode != self._mode: self._mode = mode self.notify("mode") piper-0.8/piper/resolutionrow.py000066400000000000000000000237531467456234500171560ustar00rootroot00000000000000# SPDX-License-Identifier: GPL-2.0-or-later from typing import Optional import gi from .ratbagd import RatbagdResolution from .util.gobject import connect_signal_with_weak_ref gi.require_version("Gtk", "3.0") from gi.repository import GObject, Gdk, Gtk # noqa class _DPIEntry(Gtk.Entry, Gtk.Editable): """ A subclass of Gtk.Entry with an overridden method for input validation. This class addresses a specific bug in the handling of parameters in pygobject when using signals. For Gtk.Entry, the 'position' parameter is incorrect when handling the 'insert-text' signal, causing an assertion warning to be logged. By using this subclass, we can override the 'insert-text' logic to correctly handle the position parameter and avoid the warning. Inheriting from Gtk.Editable in addition to Gtk.Entry ensures that the overridden method applies only to instances of this class, rather than affecting all Gtk.Entry objects in the application. """ __gtype_name__ = "DPIEntry" def do_insert_text(self, new_text: str, new_text_length: int, position: int) -> int: """Overrides the default Gtk.Editable insert-text handler to validate numerical input.""" if not new_text.isdigit(): self.stop_emission("insert-text") return position self.get_buffer().insert_text(position, new_text, new_text_length) return position + new_text_length @Gtk.Template(resource_path="/org/freedesktop/Piper/ui/ResolutionRow.ui") class ResolutionRow(Gtk.ListBoxRow): """A Gtk.ListBoxRow subclass containing the widgets to configure a resolution.""" __gtype_name__ = "ResolutionRow" active_button: Gtk.Button = Gtk.Template.Child() # type: ignore active_label: Gtk.Label = Gtk.Template.Child() # type: ignore disable_button: Gtk.Button = Gtk.Template.Child() # type: ignore dpi_label: Gtk.Label = Gtk.Template.Child() # type: ignore dpi_entry: _DPIEntry = Gtk.Template.Child() # type: ignore revealer: Gtk.Revealer = Gtk.Template.Child() # type: ignore scale: Gtk.Scale = Gtk.Template.Child() # type: ignore CAP_SEPARATE_XY_RESOLUTION = False CAP_DISABLE = False def __init__( self, resolution: RatbagdResolution, resolutions_page, *args, **kwargs ) -> None: Gtk.ListBoxRow.__init__(self, *args, **kwargs) self.resolutions_page = resolutions_page self._resolution = resolution self.resolutions = resolution.resolutions self._scale_handler = self.scale.connect( "value-changed", self._on_scale_value_changed ) self._disabled_button_handler = self.disable_button.connect( "toggled", self._on_disable_button_toggled ) self._active_handler = connect_signal_with_weak_ref( self, resolution, "notify::is-active", self._on_status_changed ) self._disabled_handler = connect_signal_with_weak_ref( self, resolution, "notify::is-disabled", self._on_status_changed ) connect_signal_with_weak_ref( self, resolution, "notify::resolution", self._on_profile_resolution_changed ) # Get resolution capabilities and update internal values. if RatbagdResolution.CAP_SEPARATE_XY_RESOLUTION in resolution.capabilities: self.CAP_SEPARATE_XY_RESOLUTION = True if RatbagdResolution.CAP_DISABLE in resolution.capabilities: self.CAP_DISABLE = True # Set initial values for the UI. res = resolution.resolution[0] minres = resolution.resolutions[0] maxres = resolution.resolutions[-1] res_num_chars = len(str(maxres)) # Set the max width and length for the DPI text boxes, based on the max res value. self.dpi_entry.set_width_chars(res_num_chars) self.dpi_entry.set_max_length(res_num_chars) with self.scale.handler_block(self._scale_handler): self.scale.props.adjustment.configure(res, minres, maxres, 50, 50, 0) self.scale.set_value(res) if resolution.is_disabled: with self.disable_button.handler_block(self._disabled_button_handler): self.disable_button.set_active(True) self._on_status_changed(resolution, _pspec=None) @Gtk.Template.Callback("_on_change_value") def _on_change_value( self, scale: Gtk.Scale, scroll: Gtk.ScrollType, value: float ) -> bool: # Cursor-controlled slider may get out of the GtkAdjustment's range. value = min(max(self.resolutions[0], value), self.resolutions[-1]) # Find the nearest permitted value to our Gtk.Scale value. lo = max(r for r in self.resolutions if r <= value) hi = min(r for r in self.resolutions if r >= value) value = lo if value - lo < hi - value else hi scale.set_value(value) self.dpi_entry.set_text(str(value)) # libratbag provides a fake-exponential range with the deltas # increasing as the resolution goes up. Make sure we set our # steps to the next available value. idx = self.resolutions.index(value) if idx < len(self.resolutions) - 1: delta = self.resolutions[idx + 1] - self.resolutions[idx] scale.props.adjustment.set_step_increment(delta) scale.props.adjustment.set_page_increment(delta) return True def _on_disable_button_toggled(self, togglebutton: Gtk.Button) -> None: # The disable button has been toggled, update RatbagdResolution. self._resolution.set_disabled(togglebutton.get_active()) # Update UI self._on_status_changed(self._resolution, _pspec=None) @Gtk.Template.Callback("_on_active_button_clicked") def _on_active_button_clicked(self, _togglebutton: Gtk.Button) -> None: # The set active button has been clicked, update RatbagdResolution. self._resolution.set_active() @Gtk.Template.Callback("_on_scroll_event") def _on_scroll_event(self, widget: Gtk.Widget, _event: Gdk.EventScroll) -> bool: # Prevent a scroll in the list to get caught by the scale. GObject.signal_stop_emission_by_name(widget, "scroll-event") return False def _on_scale_value_changed(self, scale: Gtk.Scale) -> None: # The scale has been moved, update RatbagdResolution's resolution. res = int(scale.get_value()) self._on_dpi_values_changed(res=res) def _on_status_changed( self, resolution: RatbagdResolution, _pspec: Optional[GObject.ParamSpec] ) -> None: # The resolution's status changed, update UI. self._on_dpi_values_changed() if resolution.is_active: self.active_label.set_visible(True) self.active_button.set_sensitive(False) self.disable_button.set_sensitive(False) else: self.active_label.set_visible(False) self.active_button.set_sensitive(True) if self.CAP_DISABLE: with self.disable_button.handler_block(self._disabled_button_handler): self.disable_button.set_sensitive(not resolution.is_default) if resolution.is_disabled: self.disable_button.set_active(True) self.active_button.set_sensitive(False) self.dpi_label.set_sensitive(False) self.dpi_entry.set_sensitive(False) self.scale.set_sensitive(False) else: self.disable_button.set_active(False) self.dpi_label.set_sensitive(True) self.dpi_entry.set_sensitive(True) self.scale.set_sensitive(True) def toggle_revealer(self) -> None: # Toggles the revealer to show or hide the configuration widgets. reveal = not self.revealer.get_reveal_child() self.revealer.set_reveal_child(reveal) if reveal: self.dpi_entry.grab_focus() def _on_dpi_values_changed(self, res: Optional[int] = None) -> None: # Freeze the notify::resolution signal from firing and # update DPI text box and resolution values. if res is None: res = self._resolution.resolution[0] new_res = (res, res) if self.CAP_SEPARATE_XY_RESOLUTION else (res,) self.dpi_entry.set_text(str(res)) # Only update new resolution if changed if new_res != self._resolution.resolution: self._resolution.resolution = new_res @Gtk.Template.Callback("_on_dpi_entry_activate") def _on_dpi_entry_activate(self, entry: Gtk.Entry) -> None: # The DPI entry has been changed, update the scale and RatbagdResolution's resolution. try: res = int(entry.get_text()) # Get the resolution closest to what has been entered closest_res = min(self.resolutions, key=lambda x: abs(x - res)) entry.set_text(str(closest_res)) self._on_dpi_values_changed(res=closest_res) with self.scale.handler_block(self._scale_handler): self.scale.set_value(res) except ValueError: # If the input is not a valid integer, reset to the current value. entry.set_text(str(self._resolution.resolution[0])) @Gtk.Template.Callback("_on_dpi_entry_focus_in") def _on_dpi_entry_focus_in(self, _entry: Gtk.Entry, _event_focus: Gdk.EventFocus): if not self.revealer.get_reveal_child(): self.resolutions_page.on_row_activated(None, self) @Gtk.Template.Callback("_on_dpi_entry_focus_out") def _on_dpi_entry_focus_out(self, entry: Gtk.Entry, _event_focus: Gdk.EventFocus): # Apply the DPI value on focus out self._on_dpi_entry_activate(entry) def _on_profile_resolution_changed( self, resolution: RatbagdResolution, _pspec: GObject.ParamSpec ) -> None: with self.scale.handler_block(self._scale_handler): res = resolution.resolution[0] self.scale.set_value(res) self.dpi_entry.set_text(str(res)) piper-0.8/piper/resolutionspage.py000066400000000000000000000060221467456234500174340ustar00rootroot00000000000000# SPDX-License-Identifier: GPL-2.0-or-later from gettext import gettext as _ from typing import Optional from .mousemap import MouseMap from .ratbagd import RatbagdButton, RatbagdDevice, RatbagdProfile from .resolutionrow import ResolutionRow import gi gi.require_version("Gtk", "3.0") from gi.repository import Gtk # noqa @Gtk.Template(resource_path="/org/freedesktop/Piper/ui/ResolutionsPage.ui") class ResolutionsPage(Gtk.Box): """The first stack page, exposing the resolution configuration with its report rate buttons and resolutions list.""" __gtype_name__ = "ResolutionsPage" _resolution_labels = [ RatbagdButton.ActionSpecial.RESOLUTION_CYCLE_UP, RatbagdButton.ActionSpecial.RESOLUTION_CYCLE_DOWN, RatbagdButton.ActionSpecial.RESOLUTION_UP, RatbagdButton.ActionSpecial.RESOLUTION_DOWN, RatbagdButton.ActionSpecial.RESOLUTION_ALTERNATE, RatbagdButton.ActionSpecial.RESOLUTION_DEFAULT, ] add_resolution_row: Gtk.ListBoxRow = Gtk.Template.Child() # type: ignore listbox: Gtk.ListBox = Gtk.Template.Child() # type: ignore def __init__( self, ratbagd_device: RatbagdDevice, profile: RatbagdProfile, *args, **kwargs ) -> None: """Instantiates a new ResolutionsPage. @param ratbag_device The ratbag device to configure, as ratbagd.RatbagdDevice """ Gtk.Box.__init__(self, *args, **kwargs) self._device = ratbagd_device self._last_activated_row: Optional[ResolutionRow] = None self._profile = profile mousemap = MouseMap("#Buttons", self._device, spacing=20, border_width=20) self.pack_start(mousemap, True, True, 0) # Place the MouseMap on the left self.reorder_child(mousemap, 0) for button in profile.buttons: if ( button.action_type == RatbagdButton.ActionType.SPECIAL and button.special in self._resolution_labels ): label = Gtk.Label( label=_(RatbagdButton.SPECIAL_DESCRIPTION[button.special]) ) mousemap.add(label, f"#button{button.index}") mousemap.show_all() self.listbox.foreach(Gtk.Widget.destroy) for resolution in profile.resolutions: row = ResolutionRow(resolution, self) self.listbox.insert(row, resolution.index) @Gtk.Template.Callback("on_row_activated") def on_row_activated(self, _listbox: Gtk.ListBox, row: ResolutionRow) -> None: if row is self._last_activated_row: self._last_activated_row = None row.toggle_revealer() else: if self._last_activated_row is not None: self._last_activated_row.toggle_revealer() if row is self.add_resolution_row: print("TODO: RatbagdProfile needs a way to add resolutions") self._last_activated_row = None else: self._last_activated_row = row row.toggle_revealer() piper-0.8/piper/svg.py000066400000000000000000000022571467456234500150160ustar00rootroot00000000000000# SPDX-License-Identifier: GPL-2.0-or-later from typing import Optional from gi.repository import Gio # noqa import configparser def get_svg(model: str) -> Optional[bytes]: resource = Gio.resources_lookup_data( "/org/freedesktop/Piper/svgs/svg-lookup.ini", Gio.ResourceLookupFlags.NONE ) data = resource.get_data() assert data is not None config = configparser.ConfigParser() config.read_string(data.decode("utf-8"), source="svg-lookup.ini") assert config.sections() filename = "fallback.svg" if model.startswith(("usb:", "bluetooth:")): bus, vid, pid, version = model.split(":") # Where the version is 0 (virtually all devices) we drop it. This # way the DeviceMatch lines are less confusing. usbid = ":".join([bus, vid, pid]) if int(version) == 0 else model for s in config.sections(): matches = config[s]["DeviceMatch"].split(";") if usbid in matches: filename = config[s]["Svg"] break resource = Gio.resources_lookup_data( f"/org/freedesktop/Piper/svgs/{filename}", Gio.ResourceLookupFlags.NONE ) return resource.get_data() piper-0.8/piper/util/000077500000000000000000000000001467456234500146145ustar00rootroot00000000000000piper-0.8/piper/util/__init__.py000066400000000000000000000000001467456234500167130ustar00rootroot00000000000000piper-0.8/piper/util/gobject.py000066400000000000000000000010621467456234500166020ustar00rootroot00000000000000from typing import Callable, Union from gi.repository import GObject def connect_signal_with_weak_ref( ref_obj: Union[GObject.Object, GObject.GObject], obj: Union[GObject.Object, GObject.GObject], signal: str, func: Callable, *args, ) -> int: """ Connect handler to an object `obj` tied to the life time of `ref_obj`. Use this to work around https://gitlab.gnome.org/GNOME/pygobject/-/issues/557. """ handler = obj.connect(signal, func, *args) ref_obj.weak_ref(lambda: obj.disconnect(handler)) return handler piper-0.8/piper/welcomeperspective.py000066400000000000000000000063271467456234500201260ustar00rootroot00000000000000# SPDX-License-Identifier: GPL-2.0-or-later from typing import List, Optional from .devicerow import DeviceRow from .ratbagd import RatbagdDevice import gi gi.require_version("Gtk", "3.0") from gi.repository import GObject, Gtk # noqa @Gtk.Template(resource_path="/org/freedesktop/Piper/ui/WelcomePerspective.ui") class WelcomePerspective(Gtk.Box): """A perspective to present a list of devices for the user to pick one to configure.""" __gtype_name__ = "WelcomePerspective" __gsignals__ = { "device-selected": ( GObject.SignalFlags.RUN_FIRST, None, (GObject.TYPE_PYOBJECT,), ), } listbox: Gtk.ListBox = Gtk.Template.Child() # type: ignore _titlebar: Gtk.HeaderBar = Gtk.Template.Child() # type: ignore def __init__(self, *args, **kwargs) -> None: """Instantiates a new WelcomePerspective.""" Gtk.Box.__init__(self, *args, **kwargs) self.listbox.set_sort_func(self._listbox_sort_func) self.listbox.set_header_func(self._listbox_header_func) def set_devices(self, devices: List[RatbagdDevice]) -> None: """Sets the devices to present to the user. @param devices The devices to present, as [ratbagd.RatbagdDevice] """ self.listbox.foreach(Gtk.Widget.destroy) for device in devices: self.add_device(device) def add_device(self, device: RatbagdDevice) -> None: """Add a device to the list. @param device The device to add, as ratbagd.RatbagdDevice """ self.listbox.add(DeviceRow(device)) def remove_device(self, device: RatbagdDevice) -> None: """Remove a device from the list. @param device The device to remove, as ratbagd.RatbagdDevice """ for child in self.listbox.get_children(): if child._device is device: child.destroy() break @GObject.Property def name(self) -> str: """The name of this perspective.""" return "welcome_perspective" @GObject.Property def titlebar(self) -> Gtk.Widget: """The titlebar to this perspective.""" return self._titlebar @GObject.Property def can_go_back(self) -> bool: """Whether this perspective wants a back button to be displayed in case there is more than one connected device.""" return False @GObject.Property def can_shutdown(self) -> bool: """Whether this perspective can safely shutdown.""" return True @Gtk.Template.Callback("_on_device_row_activated") def _on_device_row_activated(self, listbox: Gtk.ListBox, row: DeviceRow) -> None: self.emit("device-selected", row.device) def _listbox_sort_func(self, row1: DeviceRow, row2: DeviceRow) -> int: name1 = row1.device.name.casefold() name2 = row2.device.name.casefold() if name1 < name2: return -1 if name1 == name2: return 0 return 1 def _listbox_header_func( self, row: Gtk.ListBoxRow, before: Optional[Gtk.ListBoxRow] ) -> None: if before is not None: separator = Gtk.Separator(orientation=Gtk.Orientation.HORIZONTAL) row.set_header(separator) piper-0.8/piper/window.py000066400000000000000000000247301467456234500155260ustar00rootroot00000000000000# SPDX-License-Identifier: GPL-2.0-or-later from gettext import gettext as _ from typing import Callable, List, Optional from .errorperspective import ErrorPerspective from .mouseperspective import MousePerspective from .welcomeperspective import WelcomePerspective from .ratbagd import ( Ratbagd, RatbagdDevice, RatbagdIncompatibleError, RatbagdUnavailableError, ) import gi gi.require_version("Gtk", "3.0") from gi.repository import Gdk, GLib, Gtk, Gio # noqa @Gtk.Template(resource_path="/org/freedesktop/Piper/ui/Window.ui") class Window(Gtk.ApplicationWindow): """A Gtk.ApplicationWindow subclass to implement the main application window. This window displays the different perspectives (error, mouse and welcome) that each present their own behavior.""" __gtype_name__ = "Window" primary_menu: Gtk.Menu = Gtk.Template.Child() # type: ignore stack_perspectives: Gtk.Stack = Gtk.Template.Child() # type: ignore stack_titlebar: Gtk.Stack = Gtk.Template.Child() # type: ignore def __init__(self, init_ratbagd_cb: Callable[[], Ratbagd], *args, **kwargs) -> None: """Instantiates a new Window. @param ratbag The ratbag instance to connect to, as ratbagd.Ratbag """ Gtk.ApplicationWindow.__init__(self, *args, **kwargs) self.set_icon_name("org.freedesktop.Piper") self._add_perspective(ErrorPerspective(), None) try: ratbag = init_ratbagd_cb() except RatbagdUnavailableError: self._present_error_perspective( _("Cannot connect to ratbagd"), _( "Please make sure ratbagd is running and your user is in the required group" ), ) return except RatbagdIncompatibleError as e: self._present_error_perspective( _( f"Incompatible ratbagd API version (required: {e.required_version}, provided: {e.ratbagd_version})" ), _("Please update both piper and libratbag to the latest versions"), ) return for perspective in [MousePerspective(), WelcomePerspective()]: self._add_perspective(perspective, ratbag) welcome_perspective: WelcomePerspective = self._get_child("welcome_perspective") # type: ignore welcome_perspective.connect("device-selected", self._on_device_selected) ratbag.connect("device-added", self._on_device_added) ratbag.connect("device-removed", self._on_device_removed) ratbag.connect("daemon-disappeared", self._on_daemon_disappeared) if len(ratbag.devices) == 0: self._present_error_perspective( _("Cannot find any devices"), _("Please make sure your device is supported and plugged in"), ) elif len(ratbag.devices) == 1: self._present_mouse_perspective(ratbag.devices[0]) else: self._present_welcome_perspective(ratbag.devices) def do_delete_event(self, event: Gdk.Event) -> bool: for perspective in self.stack_perspectives.get_children(): if not perspective.can_shutdown: dialog = Gtk.MessageDialog( self, Gtk.DialogFlags.MODAL, Gtk.MessageType.QUESTION, Gtk.ButtonsType.YES_NO, _("There are unapplied changes. Are you sure you want to quit?"), ) response = dialog.run() dialog.destroy() if response in [Gtk.ResponseType.NO, Gtk.ResponseType.DELETE_EVENT]: return Gdk.EVENT_STOP return Gdk.EVENT_PROPAGATE def _on_daemon_disappeared(self, ratbag: Ratbagd) -> None: self._present_error_perspective( _("Ooops. ratbagd has disappeared"), _("Please restart Piper") ) def _on_device_added(self, ratbag: Ratbagd, device: RatbagdDevice) -> None: if len(ratbag.devices) == 1: # We went from 0 devices to 1 device; immediately configure it. self._present_mouse_perspective(device) elif self.stack_perspectives.get_visible_child_name() == "welcome_perspective": # We're in the welcome perspective; just add it to the list. welcome_perspective: WelcomePerspective = self._get_child( "welcome_perspective" ) # type: ignore welcome_perspective.add_device(device) else: # We're configuring another device; just notify the user. # TODO: show in-app notification? print("Device connected") def _on_device_removed(self, ratbag: Ratbagd, device: RatbagdDevice) -> None: mouse_perspective: MousePerspective = self._get_child("mouse_perspective") # type: ignore if device is mouse_perspective.device: # The current device disconnected, which can only happen from the # mouse perspective as we'd otherwise be in the welcome screen with # more than one device remaining. Hence, we display the error # perspective. self._present_error_perspective( _("Your device disconnected!"), _("Please make sure your device is plugged in"), ) elif self.stack_perspectives.get_visible_child_name() == "welcome_perspective": # We're in the welcome screen; just remove it from the list. If # there is nothing left, display the error perspective. welcome_perspective: WelcomePerspective = self._get_child("welcome_perspective") # type: ignore welcome_perspective.remove_device(device) if len(ratbag.devices) == 0: self._present_error_perspective( _("Cannot find any devices"), _("Please make sure your device is supported and plugged in"), ) else: # We're configuring another device; just notify the user. # TODO: show in-app notification? print("Device disconnected") def _add_perspective(self, perspective, ratbag: Optional[Ratbagd]) -> None: self.stack_perspectives.add_named(perspective, perspective.name) self.stack_titlebar.add_named(perspective.titlebar, perspective.name) if perspective.can_go_back: if ratbag is None: raise ValueError( "`ratbag` must be provided if the perspective can go back" ) self._perspective_add_back_button(perspective, ratbag) self._perspective_add_primary_menu(perspective) def _present_welcome_perspective(self, devices: List[RatbagdDevice]) -> None: # Present the welcome perspective for the user to select one of their # devices. welcome_perspective: WelcomePerspective = self._get_child("welcome_perspective") # type: ignore welcome_perspective.set_devices(devices) self.stack_titlebar.set_visible_child_name(welcome_perspective.name) self.stack_perspectives.set_visible_child_name(welcome_perspective.name) def _present_mouse_perspective(self, device: RatbagdDevice) -> None: # Present the mouse configuration perspective for the given device. try: mouse_perspective: MousePerspective = self._get_child("mouse_perspective") # type: ignore mouse_perspective.set_device(device) self.stack_titlebar.set_visible_child_name(mouse_perspective.name) self.stack_perspectives.set_visible_child_name(mouse_perspective.name) except ValueError as e: self._present_error_perspective(_("Cannot display device SVG"), str(e)) except GLib.Error as e: # Happens with the GetSvgFd() call when running against older # python. This can be removed when we've had the newer call out # for a while. The full error is printed to stderr by # ratbagd.py. if e.code == Gio.DBusError.UNKNOWN_METHOD: self._present_error_perspective( _("Newer version of ratbagd required"), _("Please update to the latest available version"), ) else: self._present_error_perspective( _("Unknown exception occurred"), e.message ) def _present_error_perspective(self, message: str, detail: str) -> None: # Present the error perspective informing the user of any errors. error_perspective: ErrorPerspective = self._get_child("error_perspective") # type: ignore error_perspective.set_message(message) error_perspective.set_detail(detail) self.stack_titlebar.set_visible_child_name(error_perspective.name) self.stack_perspectives.set_visible_child_name(error_perspective.name) def _on_device_selected(self, perspective, device: RatbagdDevice) -> None: self._present_mouse_perspective(device) def _get_child(self, name: str) -> Gtk.Widget: child = self.stack_perspectives.get_child_by_name(name) if child is None: raise ValueError(f"Child `{name}` was not found") return child def _perspective_add_back_button(self, perspective, ratbag: Ratbagd) -> None: button_back = Gtk.Button.new_from_icon_name( "go-previous-symbolic", Gtk.IconSize.BUTTON ) button_back.set_visible(len(ratbag.devices) > 1) button_back.connect( "clicked", lambda _, ratbag: self._present_welcome_perspective(ratbag.devices), ratbag, ) ratbag.connect( "notify::devices", lambda ratbag, _: button_back.set_visible(len(ratbag.devices) > 1), ) perspective.titlebar.add(button_back) # Place the button first in the titlebar. perspective.titlebar.child_set_property(button_back, "position", 0) def _perspective_add_primary_menu(self, perspective) -> None: hamburger = Gtk.Image.new_from_icon_name( "open-menu-symbolic", Gtk.IconSize.BUTTON ) hamburger.set_visible(True) button_primary_menu = Gtk.MenuButton.new() button_primary_menu.add(hamburger) button_primary_menu.set_visible(True) button_primary_menu.set_menu_model(self.primary_menu) perspective.titlebar.pack_end(button_primary_menu) # Place the button last in the titlebar. perspective.titlebar.child_set_property(button_primary_menu, "position", 0) piper-0.8/po/000077500000000000000000000000001467456234500131365ustar00rootroot00000000000000piper-0.8/po/LINGUAS000066400000000000000000000001551467456234500141640ustar00rootroot00000000000000# Language list must be in alphabetical order be bg cs de es fr hr it ka nl pl pt_BR ru sv uk_UA zh_CN zh_TW piper-0.8/po/POTFILES000066400000000000000000000014451467456234500143120ustar00rootroot00000000000000data/org.freedesktop.Piper.desktop.in data/org.freedesktop.Piper.appdata.xml.in.in piper/__init__.py piper/advancedpage.py piper/application.py piper/buttondialog.py piper/buttonspage.py piper/devicerow.py piper/errorperspective.py piper/leddialog.py piper/ledspage.py piper/mousemap.py piper/mouseperspective.py piper/optionbutton.py piper/profilerow.py piper/ratbagd.py piper/resolutionrow.py piper/resolutionspage.py piper/welcomeperspective.py piper/window.py data/ui/AboutDialog.ui.in data/ui/AdvancedPage.ui data/ui/ButtonDialog.ui data/ui/ButtonRow.ui data/ui/DeviceRow.ui data/ui/ErrorPerspective.ui data/ui/LedDialog.ui data/ui/MousePerspective.ui data/ui/OptionButton.ui data/ui/ProfileRow.ui data/ui/ResolutionRow.ui data/ui/ResolutionsPage.ui data/ui/WelcomePerspective.ui data/ui/Window.ui piper-0.8/po/README.md000066400000000000000000000024271467456234500144220ustar00rootroot00000000000000i18n ==== This directory contains the translations of Piper. For errors in translations, please [file an issue](https://github.com/libratbag/piper/issues/new). New or updated translations are always welcome. To start a new translation, run: $ meson translation-build $ ninja -C translation-build piper-pot # Now you can optionally remove the build directory $ rm -rf translation-build $ cp po/piper.pot po/$lang.po where `$lang` is the language code of your target language, e.g. `nl` for Dutch or `en_GB` for British English. Edit the [LINGUAS](https://github.com/libratbag/piper/blob/master/po/LINGUAS) file and add your language code, keeping the list sorted alphabetically. Finally, open the `.po` file you just created and translate all the strings. Don't forget to fill in the information in the header! To update an existing translation, run: $ meson translation-build $ ninja -C translation-build piper-update-po # Now you can optionally remove the build directory $ rm -rf translation-build and update the `po/$lang.po` file of your target language. When you are done translating, file a pull request on [GitHub](https://github.com/libratbag/piper) or, if you don't know how to, [open an issue](https://github.com/libratbag/piper/issues/new) and attach the `.po` file there. piper-0.8/po/be.po000066400000000000000000000405671467456234500141000ustar00rootroot00000000000000# Belarusian translation for Piper. # Copyright (C) 2019 Piper authors # This file is distributed under the same license as the piper package. # Aliaksei Piatrouski >, 2019. # msgid "" msgstr "" "Project-Id-Version: piper\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2019-10-26 19:46+0300\n" "PO-Revision-Date: 2019-10-26 22:23+0300\n" "Language: be\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Last-Translator: Aliaksei Piatrouski \n" "Language-Team: \n" "X-Generator: Poedit 2.2.1\n" #: data/org.freedesktop.Piper.desktop.in:3 #: data/org.freedesktop.Piper.appdata.xml.in.in:7 msgid "Piper" msgstr "Piper" #: data/org.freedesktop.Piper.desktop.in:4 #: data/org.freedesktop.Piper.appdata.xml.in.in:8 msgid "Configurable mouse configuration utility" msgstr "Прыстасаванне для наладкі мышы" #. Translators: Do NOT translate or transliterate this text (this is an icon file name)! #: data/org.freedesktop.Piper.desktop.in:7 msgid "org.freedesktop.Piper" msgstr "org.freedesktop.Piper" #. Translators: Search terms to find this application. Do NOT translate or localize the semicolons! The list MUST also end with a semicolon! #: data/org.freedesktop.Piper.desktop.in:12 msgid "gaming;configuration;mouse;mice;" msgstr "гульні;наладкі;настройкі;мыш;" #: data/org.freedesktop.Piper.appdata.xml.in.in:10 msgid "" "Piper is a graphical user interface to configure gaming mice. Configuration " "options include changing the resolution (DPI) of the mouse, adding and " "removing profiles, setting LED colors and changing button behaviors." msgstr "" "Piper - гэта графічны інтэрфэйс карыстальніка для наладкі гульнявых мышэй. " "Варыянты канфігурацыі ўключаюць змену адрознівальнай здольнасці (DPI) мышы, " "даданне і выдаленне профіляў, наладкі колеру святлодыёда і змяненне паводзін " "кнопкі." #: data/org.freedesktop.Piper.appdata.xml.in.in:16 msgid "" "Piper requires libratbag’s ratbagd, the daemon to actually communicate with " "the mice. Piper is merely a front end to ratbagd, ratbagd must be installed " "and running when Piper is launched." msgstr "" "Piper патрабуе бібліятэку libratbagd ад сэрвісу ratbagd, каб камунікаваць з " "мышшу. Piper - гэта проста графічны інтэрфэйс, ratbagd павінен быць " "усталяваны і запушчаны перад запускам Piper." #: data/org.freedesktop.Piper.appdata.xml.in.in:33 msgid "The button configuraton page" msgstr "Старонка наладкі кнопак" #: data/org.freedesktop.Piper.appdata.xml.in.in:37 msgid "The LED configuraton page" msgstr "Старонка наладкі LED" #: data/org.freedesktop.Piper.appdata.xml.in.in:41 msgid "The resolution configuraton page" msgstr "Старонка наладкі разрознасці (DPI)" #. Translators: section header for mapping one button's click to another. #: piper/buttondialog.py:141 msgid "Button mapping" msgstr "Прывязка кнопак" #. Translators: section header for assigning special functions to buttons. #: piper/buttondialog.py:150 msgid "Special mapping" msgstr "Асобная прывязка" #. Translators: the {} will be replaced with the button index, e.g. #. "Button 1 click". #: piper/buttondialog.py:222 piper/buttonspage.py:90 msgid "Button {} click" msgstr "Клік кнопкі {}" #: piper/buttonspage.py:94 msgid "Macro: {}" msgstr "Макра: {}" #. Translators: the button is turned disabled, e.g. off. #: piper/buttonspage.py:97 msgid "Disabled" msgstr "Выключана" #. Translators: the button has an unknown function. #: piper/buttonspage.py:100 piper/ratbagd.py:663 msgid "Unknown" msgstr "Невядома" #: piper/buttonspage.py:108 msgid "Configure button {}" msgstr "Наладкі кнопкі {}" #: piper/mouseperspective.py:90 data/ui/ResolutionsPage.ui:209 msgid "Resolutions" msgstr "Разрознасць" #: piper/mouseperspective.py:92 msgid "Buttons" msgstr "Кнопкі" #: piper/mouseperspective.py:94 msgid "LEDs" msgstr "LEDs" #: piper/ratbagd.py:653 msgid "Left mouse button click" msgstr "Клік левай кнопкі мышы" #: piper/ratbagd.py:654 msgid "Right mouse button click" msgstr "Клік правай кнопкі мышы" #: piper/ratbagd.py:655 msgid "Middle mouse button click" msgstr "Клік сярэдняй кнопкі мышы" #: piper/ratbagd.py:656 msgid "Backward" msgstr "Назад" #: piper/ratbagd.py:657 msgid "Forward" msgstr "Далей" #: piper/ratbagd.py:662 msgid "Invalid" msgstr "Несапраўдны" #: piper/ratbagd.py:664 msgid "Doubleclick" msgstr "Двайны клік" #: piper/ratbagd.py:665 msgid "Wheel Left" msgstr "Кола ўлева" #: piper/ratbagd.py:666 msgid "Wheel Right" msgstr "Кола ўправа" #: piper/ratbagd.py:667 msgid "Wheel Up" msgstr "Кола ўверх" #: piper/ratbagd.py:668 msgid "Wheel Down" msgstr "Кола ўніз" #: piper/ratbagd.py:669 msgid "Ratchet Mode" msgstr "Рэжым трашчоткі" #: piper/ratbagd.py:670 msgid "Cycle Resolution Up" msgstr "Цыклічна павялічыць разрознасць" #: piper/ratbagd.py:671 msgid "Cycle Resolution Down" msgstr "Цыклічна зменшыць разрознасць" #: piper/ratbagd.py:672 msgid "Resolution Up" msgstr "Павялічыць разрознасць" #: piper/ratbagd.py:673 msgid "Resolution Down" msgstr "Зменшыць разрознасць" #: piper/ratbagd.py:674 msgid "Resolution Switch" msgstr "Змяніць разрознасць" #: piper/ratbagd.py:675 msgid "Default Resolution" msgstr "Разрознасць па змоўчанні" #: piper/ratbagd.py:676 msgid "Cycle Profile Up" msgstr "Наступны профіль (цыклічна)" #: piper/ratbagd.py:677 msgid "Cycle Profile Down" msgstr "Папярэдні профіль (цыклічна)" #: piper/ratbagd.py:678 msgid "Profile Up" msgstr "Наступны профіль" #: piper/ratbagd.py:679 msgid "Profile Down" msgstr "Папярэдні профіль" #: piper/ratbagd.py:680 msgid "Second Mode" msgstr "Іншы Рэжым" #: piper/ratbagd.py:681 msgid "Battery Level" msgstr "Узровень батарэі" #. Translators: this is used when there is no macro to preview. #: piper/ratbagd.py:811 data/ui/ButtonDialog.ui:106 data/ui/ButtonDialog.ui:187 msgid "None" msgstr "Нічога" #. Translators: the LED is off. #: piper/ratbagd.py:893 data/ui/LedDialog.ui:395 msgid "Off" msgstr "Выключыць" #. Translators: the LED has a single, solid color. #: piper/ratbagd.py:895 data/ui/LedDialog.ui:66 msgid "Solid" msgstr "Адзін колер" #. Translators: the LED is cycling between red, green and blue. #: piper/ratbagd.py:897 data/ui/LedDialog.ui:189 msgid "Cycle" msgstr "Зменны колер" #. Translators: the LED's is pulsating a single color on different #. brightnesses. #: piper/ratbagd.py:900 data/ui/LedDialog.ui:355 msgid "Breathing" msgstr "Пульсацыя" #: piper/window.py:54 msgid "Cannot connect to ratbagd" msgstr "Немагчыма злучыцца з ratbagd" #: piper/window.py:55 msgid "Please make sure ratbagd is running" msgstr "Упэўніцеся, што ratbagd запушчаны" #: piper/window.py:58 msgid "Incompatible ratbagd API version (required: {}, provided: {})" msgstr "Няправільная версія ratbagdAPI (трэба: {}, знойдзена: {})" #: piper/window.py:59 msgid "Please update both piper and libratbag to the latest versions" msgstr "Калі ласка, абнавіце Piper і libratbag да апошніх весій" #: piper/window.py:73 piper/window.py:127 msgid "Cannot find any devices" msgstr "Немагчыма знайсці ніякія прылады" #: piper/window.py:74 piper/window.py:128 msgid "Please make sure your device is supported and plugged in" msgstr "Упэўніцеся, што прылада падтрымліваецца і падключана" #: piper/window.py:86 msgid "There are unapplied changes. Are you sure you want to quit?" msgstr "Ёсць непрымянёныя змены. Усё роўна выйсці?" #: piper/window.py:95 msgid "Ooops. ratbagd has disappeared" msgstr "Ой! ratbagd прапаў" #: piper/window.py:96 msgid "Please restart Piper" msgstr "Калі ласка, перазапусціце Piper" #. The current device disconnected, which can only happen from the #. mouse perspective as we'd otherwise be in the welcome screen with #. more than one device remaining. Hence, we display the error #. perspective. #: piper/window.py:119 msgid "Your device disconnected!" msgstr "Ваша прылада адключана!" #: piper/window.py:120 msgid "Please make sure your device is plugged in" msgstr "Упэўніцеся, то ваша прылада падключана" #: piper/window.py:159 msgid "Cannot display device SVG" msgstr "Немагчыма паказаць выяву прылады" #: piper/window.py:166 msgid "Newer version of ratbagd required" msgstr "Неабходна больш новая версія ratbagd" #: piper/window.py:167 msgid "Please update to the latest available version" msgstr "Калі ласка абнавіцеся да апошняй версіі" #: piper/window.py:169 msgid "Unknown exception occurred" msgstr "Адбылася невядомая памылка" #: data/ui/AboutDialog.ui.in:13 msgid "Visit Piper’s website" msgstr "Перайсці на старонку Piper" #: data/ui/AboutDialog.ui.in:14 msgid "translator-credits" msgstr "Aliaksei Piatrouski " #: data/ui/ButtonDialog.ui:65 msgid "Search for a button mapping" msgstr "Пошук прывязак кнопак" #: data/ui/ButtonDialog.ui:91 msgid "Capture a macro for this button" msgstr "Запісаць макра для гэтай кнопкі" #: data/ui/ButtonDialog.ui:104 msgid "The currently set macro" msgstr "Бягучы ўсталяваны макра" #: data/ui/ButtonDialog.ui:129 msgid "Send keystroke" msgstr "Адправіць камбінацыю клавіш" #: data/ui/ButtonDialog.ui:169 msgid "Enter a new key sequence for the macro." msgstr "Увядзіце новую паслядоўнасць клавіш для макраса." #: data/ui/ButtonDialog.ui:221 msgid "Press Escape to cancel or Return to accept." msgstr "Націсніце Escape каб адмяніць або Return каб прыняць." #: data/ui/ButtonDialog.ui:252 msgid "Set the device’s handedness." msgstr "Левая/правая рука." #: data/ui/ButtonDialog.ui:270 msgid "" "This allows you to swap the order of the primary mouse buttons. In left-" "handed mode, the physical left mouse button generates a right mouse click " "and vice versa." msgstr "" "Гэта дазваляе змяніць парадак асноўных кнопак мышы. У рэжыме левай рукі " "фізічная левая кнопка мышы працуе як правая і наадварот." #: data/ui/ButtonDialog.ui:290 msgid "Left Handed" msgstr "Левая рука" #: data/ui/ButtonDialog.ui:295 msgid "The left mouse button generates a left mouse click" msgstr "Левая кнопка мышы генеруе левы клік" #: data/ui/ButtonDialog.ui:309 msgid "Right Handed" msgstr "Правая рука" #: data/ui/ButtonDialog.ui:314 msgid "The left mouse button generates a right mouse click" msgstr "Левая кнопка мышы генеруе правы клік" #: data/ui/ButtonDialog.ui:354 data/ui/LedDialog.ui:414 msgid "Cancel" msgstr "Адмена" #: data/ui/ButtonDialog.ui:356 data/ui/LedDialog.ui:418 msgid "Ignore any changes made" msgstr "Ігнараваць усе зробленыя змены" #: data/ui/ButtonDialog.ui:362 data/ui/LedDialog.ui:430 #: data/ui/MousePerspective.ui:132 msgid "Apply" msgstr "Ужывіць" #: data/ui/ButtonDialog.ui:365 data/ui/LedDialog.ui:435 msgid "Apply any changes made" msgstr "Ужывіць усе зробленыя змены" #: data/ui/ButtonDialog.ui:405 msgid "No button mapping found" msgstr "Не знойдзена ніякіх прывязак" #: data/ui/ButtonDialog.ui:421 msgid "Try a different search" msgstr "Паспрабуйце іншае слова" #: data/ui/ErrorPerspective.ui:16 msgid "Here, rodent, rodent, rodent…" msgstr "Тут мыш, мыш, мыш…" #: data/ui/ErrorPerspective.ui:69 msgid "Uh Oh! Something went wrong…" msgstr "Ах! Нешта пайшло не так…" #: data/ui/ErrorPerspective.ui:73 data/ui/WelcomePerspective.ui:123 msgid "Quit" msgstr "Выйсці" #: data/ui/LedDialog.ui:58 data/ui/LedDialog.ui:209 msgid "Choose a color for the LED" msgstr "Абярыце колер для LED" #: data/ui/LedDialog.ui:90 data/ui/LedDialog.ui:257 msgid "Choose a brightness for the LED" msgstr "Абярыце яркасць для LED" #: data/ui/LedDialog.ui:104 data/ui/LedDialog.ui:270 msgid "Brightness" msgstr "Яркасць" #: data/ui/LedDialog.ui:135 data/ui/LedDialog.ui:301 msgid "Choose an effect duration for the LED" msgstr "Абярыце эфект для LED" #: data/ui/LedDialog.ui:153 data/ui/LedDialog.ui:319 msgid "ms" msgstr "мс" #: data/ui/LedDialog.ui:175 data/ui/LedDialog.ui:341 msgid "Effect duration" msgstr "Працягласць эфекту" #: data/ui/LedDialog.ui:212 msgid "Pick a Color for the LED" msgstr "Вызначце колер для LED" #: data/ui/LedDialog.ui:226 msgid "Color" msgstr "Колер" #: data/ui/LedDialog.ui:380 msgid "This LED is off" msgstr "Гэты LED адключаны" #: data/ui/MousePerspective.ui:44 msgid "Something went wrong. The device has been reset to a previous state." msgstr "Нешта пайшло не так. Прылада была адноўлена ў папярэдні стан." #: data/ui/MousePerspective.ui:101 msgid "Select another profile" msgstr "Абярыце іншы профіль" #: data/ui/MousePerspective.ui:126 msgid "Commit the changes to the device" msgstr "Адправіць змены ў прыладу" #: data/ui/MousePerspective.ui:170 msgid "Click to switch to another profile" msgstr "Клікніце каб абраць іншы профіль" #: data/ui/MousePerspective.ui:185 msgid "Add profile" msgstr "Дадаць профіль" #: data/ui/MousePerspective.ui:189 msgid "Add a new profile to the device" msgstr "Дадаць новы профіль да прылады" #: data/ui/OptionButton.ui:9 msgid "Open the configuration dialog" msgstr "Адкрыць дыялог наладкаў" #: data/ui/ProfileRow.ui:16 msgid "Remove this profile from the device" msgstr "Выдаліць гэты профіль з прылады" #. Translators: this is used to indicate the active resolution. #: data/ui/ResolutionRow.ui:37 msgid "Active" msgstr "Актыўны" #: data/ui/ResolutionRow.ui:77 msgid "Set this resolution’s DPI" msgstr "Вызначыць разрознасць DPI" #. Translators: the rate at which the device reports movement. #: data/ui/ResolutionsPage.ui:43 msgid "Report rate" msgstr "Хуткасць водгуку" #: data/ui/ResolutionsPage.ui:60 msgid "Change the profile’s report rate" msgstr "Змяніць профіль хуткасці водгуку" #: data/ui/ResolutionsPage.ui:105 msgid "Hz" msgstr "Гц" #. Translators: the sensitivity of the device's sensor. #: data/ui/ResolutionsPage.ui:125 msgid "Sensitivity" msgstr "Адчувальнасць" #: data/ui/ResolutionsPage.ui:174 msgid "Add a new resolution to the profile" msgstr "Дадаць новую разрознасць да профілю" #: data/ui/WelcomePerspective.ui:20 msgid "Welcome" msgstr "Вітаем" #: data/ui/WelcomePerspective.ui:38 msgctxt "A subtitle under the \"Welcome\" title." msgid "Select a device to configure it" msgstr "Абярыце прыстасаванне для наладкі" #: data/ui/WelcomePerspective.ui:89 msgctxt "A tooltip over the list of devices." msgid "Select a device to configure it" msgstr "Абярыце прыстасаванне для наладкі" #: data/ui/WelcomePerspective.ui:119 msgid "Select a Device" msgstr "Абраць прыладу" #: data/ui/Window.ui:8 msgid "_About Piper" msgstr "_Пра Piper" piper-0.8/po/bg.po000077500000000000000000000446631467456234500141060ustar00rootroot00000000000000# Bulgarian translation for Piper # Copyright (C) 2017-2019 Piper developers # This file is distributed under the same license as the piper package. # Lyubomir Vasilev , 2019. # msgid "" msgstr "" "Project-Id-Version: piper\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2020-01-27 23:39+0200\n" "PO-Revision-Date: 2020-01-27 23:40+0200\n" "Last-Translator: Lyubomir Vasilev \n" "Language-Team: Bulgarian <>\n" "Language: bg\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: Poedit 2.0.6\n" #: data/org.freedesktop.Piper.desktop.in:3 #: data/org.freedesktop.Piper.appdata.xml.in.in:7 msgid "Piper" msgstr "Piper" #: data/org.freedesktop.Piper.desktop.in:4 #: data/org.freedesktop.Piper.appdata.xml.in.in:8 msgid "Configurable mouse configuration utility" msgstr "Инструмент за управление на настройките на мишката" #. Translators: Do NOT translate or transliterate this text (this is an icon file name)! #: data/org.freedesktop.Piper.desktop.in:7 msgid "org.freedesktop.Piper" msgstr "org.freedesktop.Piper" #. Translators: Search terms to find this application. Do NOT translate or localize the semicolons! The list MUST also end with a semicolon! #: data/org.freedesktop.Piper.desktop.in:12 msgid "gaming;configuration;mouse;mice;" msgstr "игра;игри;гейминг;настройка;настройки;конфигурация;мишка;мишки;" #: data/org.freedesktop.Piper.appdata.xml.in.in:10 msgid "" "Piper is a graphical user interface to configure gaming mice. Configuration " "options include changing the resolution (DPI) of the mouse, adding and " "removing profiles, setting LED colors and changing button behaviors." msgstr "" "Piper е програма за управление на настройките на мишки, предназначени за " "ползване в игри. С Piper можете да променяте разделителната способност на " "мишката (DPI), да добавяте и премахвате профили, да задавате цветовете на " "светодиодите и да променяте това какво правят бутоните." #: data/org.freedesktop.Piper.appdata.xml.in.in:16 msgid "" "Piper requires libratbag’s ratbagd, the daemon to actually communicate with " "the mice. Piper is merely a front end to ratbagd, ratbagd must be installed " "and running when Piper is launched." msgstr "" "Piper изисква ratbagd – демон, който всъщност осъществява връзката с " "мишката. Piper е само потребителски интерфейс за ratbagd, и за да " "функционира, трябва ratbagd да е инсталиран и да работи при стартирането на " "Piper." #: data/org.freedesktop.Piper.appdata.xml.in.in:33 msgid "The button configuraton page" msgstr "Страницата за настройка на бутоните" #: data/org.freedesktop.Piper.appdata.xml.in.in:37 msgid "The LED configuraton page" msgstr "Страницата за настройка на светодиодите" #: data/org.freedesktop.Piper.appdata.xml.in.in:41 msgid "The resolution configuraton page" msgstr "Страницата за настройка на разделителната способност" #. Translators: section header for mapping one button's click to another. #: piper/buttondialog.py:141 msgid "Button mapping" msgstr "Съответствие на бутона" #. Translators: section header for assigning special functions to buttons. #: piper/buttondialog.py:150 msgid "Special mapping" msgstr "Специално съответствие" #. Translators: the {} will be replaced with the button index, e.g. #. "Button 1 click". #: piper/buttondialog.py:222 piper/buttonspage.py:90 msgid "Button {} click" msgstr "Щракване на бутон {}" #: piper/buttonspage.py:94 msgid "Macro: {}" msgstr "Комбинация: {}" #. Translators: the button is turned disabled, e.g. off. #: piper/buttonspage.py:97 msgid "Disabled" msgstr "Изключено" #. Translators: the button has an unknown function. #: piper/buttonspage.py:100 piper/ratbagd.py:665 msgid "Unknown" msgstr "Неизвестно" #: piper/buttonspage.py:108 msgid "Configure button {}" msgstr "Настройване на бутон {}" #: piper/mouseperspective.py:90 data/ui/ResolutionsPage.ui:209 msgid "Resolutions" msgstr "Разделителни способности" #: piper/mouseperspective.py:92 msgid "Buttons" msgstr "Бутони" #: piper/mouseperspective.py:94 msgid "LEDs" msgstr "Светодиоди" #: piper/ratbagd.py:655 msgid "Left mouse button click" msgstr "Натискане на левия бутон" #: piper/ratbagd.py:656 msgid "Right mouse button click" msgstr "Натискане на десния бутон" #: piper/ratbagd.py:657 msgid "Middle mouse button click" msgstr "Натискане на средния бутон" #: piper/ratbagd.py:658 msgid "Backward" msgstr "Назад" #: piper/ratbagd.py:659 msgid "Forward" msgstr "Напред" #: piper/ratbagd.py:664 msgid "Invalid" msgstr "Грешно" #: piper/ratbagd.py:666 msgid "Doubleclick" msgstr "Двукратно щракване" #: piper/ratbagd.py:667 msgid "Wheel Left" msgstr "Колелце наляво" #: piper/ratbagd.py:668 msgid "Wheel Right" msgstr "Колелце надясно" #: piper/ratbagd.py:669 msgid "Wheel Up" msgstr "Колелце нагоре" #: piper/ratbagd.py:670 msgid "Wheel Down" msgstr "Колелце надолу" #: piper/ratbagd.py:671 msgid "Ratchet Mode" msgstr "Постъпково въртене" #: piper/ratbagd.py:672 msgid "Cycle Resolution Up" msgstr "Разделителна способност при превъртане нагоре" #: piper/ratbagd.py:673 msgid "Cycle Resolution Down" msgstr "Разделителна способност при превъртане надолу" #: piper/ratbagd.py:674 msgid "Resolution Up" msgstr "Разделителна способност нагоре" #: piper/ratbagd.py:675 msgid "Resolution Down" msgstr "Разделителна способност надолу" #: piper/ratbagd.py:676 msgid "Resolution Switch" msgstr "Превключване на разделителната способност" #: piper/ratbagd.py:677 msgid "Default Resolution" msgstr "Разделителна способност по подразбиране" #: piper/ratbagd.py:678 msgid "Cycle Profile Up" msgstr "Превъртане на профила нагоре" #: piper/ratbagd.py:679 msgid "Cycle Profile Down" msgstr "Превъртане на профила надолу" #: piper/ratbagd.py:680 msgid "Profile Up" msgstr "Профил нагоре" #: piper/ratbagd.py:681 msgid "Profile Down" msgstr "Профил надолу" #: piper/ratbagd.py:682 msgid "Second Mode" msgstr "Втори режим" #: piper/ratbagd.py:683 msgid "Battery Level" msgstr "Заряд на батерията" #. Translators: this is used when there is no macro to preview. #: piper/ratbagd.py:813 data/ui/ButtonDialog.ui:106 data/ui/ButtonDialog.ui:187 msgid "None" msgstr "Няма" #. Translators: the LED is off. #: piper/ratbagd.py:895 data/ui/LedDialog.ui:395 msgid "Off" msgstr "Изключено" #. Translators: the LED has a single, solid color. #: piper/ratbagd.py:897 data/ui/LedDialog.ui:66 msgid "Solid" msgstr "Постоянен" #. Translators: the LED is cycling between red, green and blue. #: piper/ratbagd.py:899 data/ui/LedDialog.ui:189 msgid "Cycle" msgstr "Цикъл" #. Translators: the LED's is pulsating a single color on different #. brightnesses. #: piper/ratbagd.py:902 data/ui/LedDialog.ui:355 msgid "Breathing" msgstr "Пулсиране" #: piper/window.py:54 msgid "Cannot connect to ratbagd" msgstr "Не може да се установи връзка с ratbagd" #: piper/window.py:55 msgid "" "Please make sure ratbagd is running and your user is in the required group" msgstr "" "Моля, уверете се, че ratbagd работи и че потребителят Ви е в нужната група" #: piper/window.py:58 msgid "Incompatible ratbagd API version (required: {}, provided: {})" msgstr "Несъвместима версия на ППИ на ratbagd (необходима: {}, налична: {})" #: piper/window.py:59 msgid "Please update both piper and libratbag to the latest versions" msgstr "Моля, обновете piper и libratbag до последните им версии" #: piper/window.py:73 piper/window.py:127 msgid "Cannot find any devices" msgstr "Няма открити усройства" #: piper/window.py:74 piper/window.py:128 msgid "Please make sure your device is supported and plugged in" msgstr "Уверете се, че устройството се поддържа и че е свързано" #: piper/window.py:86 msgid "There are unapplied changes. Are you sure you want to quit?" msgstr "Няма неприложени промени. Наистина ли искате да излезете?" #: piper/window.py:95 msgid "Ooops. ratbagd has disappeared" msgstr "Опа, ratbagd изчезна" #: piper/window.py:96 msgid "Please restart Piper" msgstr "Моля, рестартирайте Piper" #. The current device disconnected, which can only happen from the #. mouse perspective as we'd otherwise be in the welcome screen with #. more than one device remaining. Hence, we display the error #. perspective. #: piper/window.py:119 msgid "Your device disconnected!" msgstr "Устройството се разкачи!" #: piper/window.py:120 msgid "Please make sure your device is plugged in" msgstr "Уверете се, че устройството е свързано" #: piper/window.py:159 msgid "Cannot display device SVG" msgstr "Не може да бъде показана графика на устройството" #: piper/window.py:166 msgid "Newer version of ratbagd required" msgstr "Изисква се по-нова версия на ratbagd" #: piper/window.py:167 msgid "Please update to the latest available version" msgstr "Моля, обновете до най-новата версия" #: piper/window.py:169 msgid "Unknown exception occurred" msgstr "Възникна неизвестно изключение" #: data/ui/AboutDialog.ui.in:10 msgid "Version: @version@" msgstr "Версия: @version@" #: data/ui/AboutDialog.ui.in:12 msgid "Visit Piper on GitHub" msgstr "Посетете Piper в GitHub" #: data/ui/AboutDialog.ui.in:13 msgid "translator-credits" msgstr "Любомир Василев" #: data/ui/ButtonDialog.ui:65 msgid "Search for a button mapping" msgstr "Търсене за съответствие на бутон" #: data/ui/ButtonDialog.ui:91 msgid "Capture a macro for this button" msgstr "Запис на комбинация за бутона" #: data/ui/ButtonDialog.ui:104 msgid "The currently set macro" msgstr "Текущата комбинация" #: data/ui/ButtonDialog.ui:129 msgid "Send keystroke" msgstr "Натискане на клавиш" #: data/ui/ButtonDialog.ui:169 msgid "Enter a new key sequence for the macro." msgstr "Въведете нова клавишна последователност за комбинацията." #: data/ui/ButtonDialog.ui:221 msgid "Press Escape to cancel or Return to accept." msgstr "Натиснете Escape за отказ или Enter за потвърждение." #: data/ui/ButtonDialog.ui:252 msgid "Set the device’s handedness." msgstr "Изберете дали устройството се ползва с лява или дясна ръка." #: data/ui/ButtonDialog.ui:270 msgid "" "This allows you to swap the order of the primary mouse buttons. In left-" "handed mode, the physical left mouse button generates a right mouse click " "and vice versa." msgstr "" "Това позволява да размените действията на основните бутони на мишката. При " "режим за лява ръка, реалният ляв бутон на мишката действа като десен в " "програмите, и обратното." #: data/ui/ButtonDialog.ui:290 msgid "Left Handed" msgstr "За лява ръка" #: data/ui/ButtonDialog.ui:295 msgid "The left mouse button generates a left mouse click" msgstr "Левият бутон на мишката действа като щракване с ляв бутон" #: data/ui/ButtonDialog.ui:309 msgid "Right Handed" msgstr "За дясна ръка" #: data/ui/ButtonDialog.ui:314 msgid "The left mouse button generates a right mouse click" msgstr "Левият бутон на мишката действа като щракване с десен бутон" #: data/ui/ButtonDialog.ui:354 data/ui/LedDialog.ui:414 msgid "Cancel" msgstr "Отказ" #: data/ui/ButtonDialog.ui:356 data/ui/LedDialog.ui:418 msgid "Ignore any changes made" msgstr "Отхвърляне на направените промени" #: data/ui/ButtonDialog.ui:362 data/ui/LedDialog.ui:430 #: data/ui/MousePerspective.ui:132 msgid "Apply" msgstr "Прилагане" #: data/ui/ButtonDialog.ui:365 data/ui/LedDialog.ui:435 msgid "Apply any changes made" msgstr "Прилагане на направените промени" #: data/ui/ButtonDialog.ui:405 msgid "No button mapping found" msgstr "Няма намерени съответствия на бутони" #: data/ui/ButtonDialog.ui:421 msgid "Try a different search" msgstr "Опитайте друго търсене" #: data/ui/ErrorPerspective.ui:16 msgid "Here, rodent, rodent, rodent…" msgstr "Тук, миши, миши…" #: data/ui/ErrorPerspective.ui:69 msgid "Uh Oh! Something went wrong…" msgstr "Опа! нещо се обърка…" #: data/ui/ErrorPerspective.ui:73 data/ui/WelcomePerspective.ui:123 msgid "Quit" msgstr "Изход" #: data/ui/LedDialog.ui:58 data/ui/LedDialog.ui:209 msgid "Choose a color for the LED" msgstr "Изберете цвят за светодиода" #: data/ui/LedDialog.ui:90 data/ui/LedDialog.ui:257 msgid "Choose a brightness for the LED" msgstr "Изберете яркост за светодиода" #: data/ui/LedDialog.ui:104 data/ui/LedDialog.ui:270 msgid "Brightness" msgstr "Яркост" #: data/ui/LedDialog.ui:135 data/ui/LedDialog.ui:301 msgid "Choose an effect duration for the LED" msgstr "Изберете продължителността на ефекта за светодиода" #: data/ui/LedDialog.ui:153 data/ui/LedDialog.ui:319 msgid "ms" msgstr "мсек" #: data/ui/LedDialog.ui:175 data/ui/LedDialog.ui:341 msgid "Effect duration" msgstr "Продължителност на ефекта" #: data/ui/LedDialog.ui:212 msgid "Pick a Color for the LED" msgstr "Изберете цвят за светодиода" #: data/ui/LedDialog.ui:226 msgid "Color" msgstr "Цвят" #: data/ui/LedDialog.ui:380 msgid "This LED is off" msgstr "Светодиодът е изключен" #: data/ui/MousePerspective.ui:44 msgid "Something went wrong. The device has been reset to a previous state." msgstr "Нещо се обърка. Устройството беше върнато към предишните настройки." #: data/ui/MousePerspective.ui:101 msgid "Select another profile" msgstr "Избор на друг профил" #: data/ui/MousePerspective.ui:126 msgid "Commit the changes to the device" msgstr "Изпращане на промените към устройството" #: data/ui/MousePerspective.ui:170 msgid "Click to switch to another profile" msgstr "Щракнете за превключване към друг профил" #: data/ui/MousePerspective.ui:185 msgid "Add profile" msgstr "Добавяне на профил" #: data/ui/MousePerspective.ui:189 msgid "Add a new profile to the device" msgstr "Добавяне на нов профил за устройството" #: data/ui/OptionButton.ui:9 msgid "Open the configuration dialog" msgstr "Отваряне на прозореца с настройките" #: data/ui/ProfileRow.ui:16 msgid "Remove this profile from the device" msgstr "Премахване на този профил от устройството" #. Translators: this is used to indicate the active resolution. #: data/ui/ResolutionRow.ui:37 msgid "Active" msgstr "Избрано" #: data/ui/ResolutionRow.ui:77 msgid "Set this resolution’s DPI" msgstr "Задаване на тази разделителна способност" #. Translators: the rate at which the device reports movement. #: data/ui/ResolutionsPage.ui:43 msgid "Report rate" msgstr "Честота на опресняване" #: data/ui/ResolutionsPage.ui:60 msgid "Change the profile’s report rate" msgstr "Промяна на честотата на опресняване за профила" #: data/ui/ResolutionsPage.ui:105 msgid "Hz" msgstr "Hz" #. Translators: the sensitivity of the device's sensor. #: data/ui/ResolutionsPage.ui:125 msgid "Sensitivity" msgstr "Чувствителност" #: data/ui/ResolutionsPage.ui:174 msgid "Add a new resolution to the profile" msgstr "Добавяне на нова разделителна способност в профила" #: data/ui/WelcomePerspective.ui:20 msgid "Welcome" msgstr "Добре дошли" #: data/ui/WelcomePerspective.ui:38 msgctxt "A subtitle under the \"Welcome\" title." msgid "Select a device to configure it" msgstr "Изберете устройство, за да го настроите" #: data/ui/WelcomePerspective.ui:89 msgctxt "A tooltip over the list of devices." msgid "Select a device to configure it" msgstr "Изберете устройство, за да го настроите" #: data/ui/WelcomePerspective.ui:119 msgid "Select a Device" msgstr "Изберете устройство" #: data/ui/Window.ui:8 msgid "_About Piper" msgstr "_Относно Piper" piper-0.8/po/cs.po000066400000000000000000000346341467456234500141150ustar00rootroot00000000000000# Czech translation for Piper. # Copyright (C) 2017-2022 Piper developres # This file is distributed under the same license as the piper package. # Štěpán Šebestian , 2022. # #, fuzzy msgid "" msgstr "" "Project-Id-Version: piper\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2022-07-04 21:48+0200\n" "PO-Revision-Date: 2022-07-04 22:29+0200\n" "Last-Translator: Štěpán Šebestian \n" "Language-Team: \n" "Language: cs\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: data/org.freedesktop.Piper.desktop.in:3 msgid "Piper" msgstr "Piper" #: data/org.freedesktop.Piper.desktop.in:4 msgid "Configurable mouse configuration utility" msgstr "Konfigurovatelný nástroj pro konfiguraci myši" #. Translators: Search terms to find this application. Do NOT translate or localize the semicolons! The list MUST also end with a semicolon! #: data/org.freedesktop.Piper.desktop.in:12 msgid "gaming;configuration;mouse;mice;" msgstr "" #: data/org.freedesktop.Piper.appdata.xml.in.in:8 msgid "Gaming mouse configuration utility" msgstr "Konfigurační nástroj pro herní myši" #: data/org.freedesktop.Piper.appdata.xml.in.in:10 msgid "" "Piper is a graphical user interface to configure gaming mice. Configuration " "options include changing the resolution (DPI) of the mouse, adding and " "removing profiles, setting LED colors and changing button behaviors." msgstr "" "Piper je grafické uživatelské rozhraní pro konfiguraci herních myši. Konfigurační " "možnosti zahrnují změny rozlišení (DPI) myši, přidávání a " "odebírání profilů, nastavení barev LED a změny chování tlačítek." #: data/org.freedesktop.Piper.appdata.xml.in.in:16 msgid "" "Piper requires libratbag’s ratbagd, the daemon to actually communicate with " "the mice. Piper is merely a front end to ratbagd, ratbagd must be installed " "and running when Piper is launched." msgstr "" "Piper vyžaduje ratbagd z libratbag, démon, který ve skutečnosti komunikuje s " "myší. Piper je jen frontend pro ratbagd, ratbagd musí být nainstalován " "a spuštěn když je spuštěn Piper." #: data/org.freedesktop.Piper.appdata.xml.in.in:27 msgid "The button configuraton page" msgstr "Stránka konfigurace tlačítek" #: data/org.freedesktop.Piper.appdata.xml.in.in:31 msgid "The LED configuraton page" msgstr "Stránka konfigurace LED" #: data/org.freedesktop.Piper.appdata.xml.in.in:35 msgid "The resolution configuraton page" msgstr "Stránka konfigurace rozlišení" #. Translators: section header for mapping one button's click to another. #: piper/buttondialog.py:127 msgid "Button mapping" msgstr "Mapování tlačítek" #. Translators: section header for assigning special functions to buttons. #: piper/buttondialog.py:136 msgid "Special mapping" msgstr "Speciální mapování" #. Translators: the {} will be replaced with the button index, e.g. #. "Button 1 click". #: piper/buttondialog.py:208 piper/buttonspage.py:76 msgid "Button {} click" msgstr "Kliknutí tlačítka {}" #: piper/buttonspage.py:80 msgid "Macro: {}" msgstr "Makro: {}" #. Translators: the button is turned disabled, e.g. off. #: piper/buttonspage.py:83 msgid "Disabled" msgstr "Zakázáno" #. Translators: the button has an unknown function. #: piper/buttonspage.py:86 piper/ratbagd.py:669 msgid "Unknown" msgstr "Neznámé" #: piper/buttonspage.py:94 msgid "Configure button {}" msgstr "Konfigurovat tlačítko {}" #: piper/mouseperspective.py:76 data/ui/ResolutionsPage.ui:240 msgid "Resolutions" msgstr "Rozlišení" #: piper/mouseperspective.py:78 msgid "Buttons" msgstr "Tlačítka" #: piper/mouseperspective.py:80 msgid "LEDs" msgstr "LED" #: piper/ratbagd.py:659 msgid "Left mouse button click" msgstr "Kliknutí levým tlačítkem myši" #: piper/ratbagd.py:660 msgid "Right mouse button click" msgstr "Kliknutí pravým tlačítkem myši" #: piper/ratbagd.py:661 msgid "Middle mouse button click" msgstr "Kliknutí prostředním tlačítkem myši" #: piper/ratbagd.py:662 msgid "Backward" msgstr "Zpět" #: piper/ratbagd.py:663 msgid "Forward" msgstr "Vpřed" #: piper/ratbagd.py:668 msgid "Invalid" msgstr "Neplatné" #: piper/ratbagd.py:670 msgid "Doubleclick" msgstr "Dvojité kliknutí" #: piper/ratbagd.py:671 msgid "Wheel Left" msgstr "Kolečko doleva" #: piper/ratbagd.py:672 msgid "Wheel Right" msgstr "Kolečko doprava" #: piper/ratbagd.py:673 msgid "Wheel Up" msgstr "Kolečko nahoru" #: piper/ratbagd.py:674 msgid "Wheel Down" msgstr "Kolečko dolů" #: piper/ratbagd.py:675 # Translation taken from Logitech documentation for MX Master 3S msgid "Ratchet Mode" msgstr "Režim po krocích" #: piper/ratbagd.py:676 msgid "Cycle Resolution Up" msgstr "Cyklus Zvýšit rozlišení" #: piper/ratbagd.py:677 msgid "Cycle Resolution Down" msgstr "Cyklus Snížit rozlišení" #: piper/ratbagd.py:678 msgid "Resolution Up" msgstr "Zvýšit rozlišení" #: piper/ratbagd.py:679 msgid "Resolution Down" msgstr "Snížit rozlišení" #: piper/ratbagd.py:680 msgid "Resolution Switch" msgstr "Přepnout rozlišení" #: piper/ratbagd.py:681 msgid "Default Resolution" msgstr "Výchozí rozlišení" #: piper/ratbagd.py:682 msgid "Cycle Profile Up" msgstr "Cyklus Další profil" #: piper/ratbagd.py:683 msgid "Cycle Profile Down" msgstr "Cyklus Předchozí profil" #: piper/ratbagd.py:684 msgid "Profile Up" msgstr "Další profil" #: piper/ratbagd.py:685 msgid "Profile Down" msgstr "Předchozí profil" #: piper/ratbagd.py:686 msgid "Second Mode" msgstr "Druhý režim" #: piper/ratbagd.py:687 msgid "Battery Level" msgstr "Úroveň baterie" #. Translators: this is used when there is no macro to preview. #: piper/ratbagd.py:817 data/ui/ButtonDialog.ui:106 data/ui/ButtonDialog.ui:187 msgid "None" msgstr "Žádné" #. Translators: the LED is off. #: piper/ratbagd.py:899 data/ui/LedDialog.ui:395 msgid "Off" msgstr "Vypnuto" #. Translators: the LED has a single, solid color. #: piper/ratbagd.py:901 data/ui/LedDialog.ui:66 msgid "Solid" msgstr "Solidní" #. Translators: the LED is cycling between red, green and blue. #: piper/ratbagd.py:903 data/ui/LedDialog.ui:189 msgid "Cycle" msgstr "Cyklus" #. Translators: the LED's is pulsating a single color on different #. brightnesses. #: piper/ratbagd.py:906 data/ui/LedDialog.ui:355 msgid "Breathing" msgstr "Dýchání" #: piper/window.py:42 msgid "Cannot connect to ratbagd" msgstr "Nepodařilo se připojit k ratbagd" #: piper/window.py:43 msgid "" "Please make sure ratbagd is running and your user is in the required group" msgstr "" "Prosím, ujistěte se že ratbagd běží a váš uživatel je v požadované skupině" #: piper/window.py:46 msgid "Incompatible ratbagd API version (required: {}, provided: {})" msgstr "Nekompatibilní verze API ratbagd (požadovaná: {}, poskytnutá: {})" #: piper/window.py:47 msgid "Please update both piper and libratbag to the latest versions" msgstr "Prosím, aktualizujte piper i libratbag na nejnovější verzi" #: piper/window.py:61 piper/window.py:115 msgid "Cannot find any devices" msgstr "Nepodařilo se najít žádné zařízení" #: piper/window.py:62 piper/window.py:116 msgid "Please make sure your device is supported and plugged in" msgstr "Prosím, ujistěte se, že vaše zařízení je podporované a připojené" #: piper/window.py:74 msgid "There are unapplied changes. Are you sure you want to quit?" msgstr "Máte neuložené změny. Opravdu chcete ukončit?" #: piper/window.py:83 msgid "Ooops. ratbagd has disappeared" msgstr "Ooops. ratbagd se ztratil" #: piper/window.py:84 msgid "Please restart Piper" msgstr "Prosím, restartujte Piper" #. The current device disconnected, which can only happen from the #. mouse perspective as we'd otherwise be in the welcome screen with #. more than one device remaining. Hence, we display the error #. perspective. #: piper/window.py:107 msgid "Your device disconnected!" msgstr "Vaše zařízení se odpojilo!" #: piper/window.py:108 msgid "Please make sure your device is plugged in" msgstr "Prosím, ujistěte se že vaše zařízení je připojené" #: piper/window.py:147 msgid "Cannot display device SVG" msgstr "Nepodařilo se zobrazit SVG zařízení" #: piper/window.py:154 msgid "Newer version of ratbagd required" msgstr "Je vyžádována novější verze ratbagd" #: piper/window.py:155 msgid "Please update to the latest available version" msgstr "Prosím, aktualizujte na nejnovější dostupnou verzi" #: piper/window.py:157 msgid "Unknown exception occurred" msgstr "Stala se neznámá chyba" #: data/ui/AboutDialog.ui.in:10 msgid "Version: @version@" msgstr "Verze: @version@" #: data/ui/AboutDialog.ui.in:12 msgid "Visit Piper on GitHub" msgstr "Navštivte Piper na GitHubu" #: data/ui/AboutDialog.ui.in:13 msgid "translator-credits" msgstr "Přeložili" #: data/ui/ButtonDialog.ui:65 msgid "Search for a button mapping" msgstr "Vyhledat mapování tlačítka" #: data/ui/ButtonDialog.ui:91 msgid "Capture a macro for this button" msgstr "Nahrát makro pro toto tlačítko" #: data/ui/ButtonDialog.ui:104 msgid "The currently set macro" msgstr "Aktuálně nastavené makro" #: data/ui/ButtonDialog.ui:129 msgid "Send keystroke" msgstr "Stisknout klávesu" #: data/ui/ButtonDialog.ui:169 msgid "Enter a new key sequence for the macro." msgstr "Zadejte novou sekvenci kláves pro toto makro." #: data/ui/ButtonDialog.ui:235 msgid "Set the device’s handedness." msgstr "Nastavte, ve které ruce zařízení držíte." #: data/ui/ButtonDialog.ui:253 msgid "" "This allows you to swap the order of the primary mouse buttons. In left-" "handed mode, the physical left mouse button generates a right mouse click " "and vice versa." msgstr "" "Toto vám umožní změnit pořadí primárních tlačítek myši. V režimu pro leváky, " "fyzické levé tlačítko myši vygeneruje kliknutí pravým tlačítkem myši " "a naopak." #: data/ui/ButtonDialog.ui:273 msgid "Left Handed" msgstr "Režim pro leváky" #: data/ui/ButtonDialog.ui:278 msgid "The left mouse button generates a left mouse click" msgstr "Levé tlačítko myši generuje kliknutí levým tlačítkem myši" #: data/ui/ButtonDialog.ui:292 msgid "Right Handed" msgstr "Režim pro praváky" #: data/ui/ButtonDialog.ui:297 msgid "The left mouse button generates a right mouse click" msgstr "Levé tlačítko myši generuje kliknutí pravým tlačítkem myši" #: data/ui/ButtonDialog.ui:337 data/ui/LedDialog.ui:414 msgid "Cancel" msgstr "Zrušit" #: data/ui/ButtonDialog.ui:339 data/ui/LedDialog.ui:418 msgid "Ignore any changes made" msgstr "Ignoruje jakékoliv provedené změny" #: data/ui/ButtonDialog.ui:345 data/ui/LedDialog.ui:430 #: data/ui/MousePerspective.ui:132 msgid "Apply" msgstr "Použít" #: data/ui/ButtonDialog.ui:348 data/ui/LedDialog.ui:435 msgid "Apply any changes made" msgstr "Použije jakékoliv provedené změny" #: data/ui/ButtonDialog.ui:388 msgid "No button mapping found" msgstr "Nebylo nalezeno žádné mapování tlačítek" #: data/ui/ButtonDialog.ui:404 msgid "Try a different search" msgstr "Zkuste jiné vyhledávání" #: data/ui/ErrorPerspective.ui:16 msgid "Here, rodent, rodent, rodent…" msgstr "Tady, hlodavče, hlodavče, hlodavče..." #: data/ui/ErrorPerspective.ui:69 msgid "Uh Oh! Something went wrong…" msgstr "Ale ne! Něco se pokazilo" #: data/ui/ErrorPerspective.ui:73 data/ui/WelcomePerspective.ui:123 msgid "Quit" msgstr "Ukončit" #: data/ui/LedDialog.ui:58 data/ui/LedDialog.ui:209 msgid "Choose a color for the LED" msgstr "Vyberte barvu pro LED" #: data/ui/LedDialog.ui:90 data/ui/LedDialog.ui:257 msgid "Choose a brightness for the LED" msgstr "Vyberte jas pro LED" #: data/ui/LedDialog.ui:104 data/ui/LedDialog.ui:270 msgid "Brightness" msgstr "Jas" #: data/ui/LedDialog.ui:135 data/ui/LedDialog.ui:301 msgid "Choose an effect duration for the LED" msgstr "Vyberte délku trvání efektu pro LED" #: data/ui/LedDialog.ui:153 data/ui/LedDialog.ui:319 msgid "ms" msgstr "ms" #: data/ui/LedDialog.ui:175 data/ui/LedDialog.ui:341 msgid "Effect duration" msgstr "Délka trvání efektu" #: data/ui/LedDialog.ui:212 msgid "Pick a Color for the LED" msgstr "Vyberte barvu pro LED" #: data/ui/LedDialog.ui:226 msgid "Color" msgstr "Barva" #: data/ui/LedDialog.ui:380 msgid "This LED is off" msgstr "Tato LED je vypnutá" #: data/ui/MousePerspective.ui:44 msgid "Something went wrong. The device has been reset to a previous state." msgstr "Něco se pokazilo. Zařízení bylo resetováno do předchozího stavu." #: data/ui/MousePerspective.ui:101 msgid "Select another profile" msgstr "Vyberte jiný profil" #: data/ui/MousePerspective.ui:126 msgid "Commit the changes to the device" msgstr "Zapsat změny do zařízení" #: data/ui/MousePerspective.ui:170 msgid "Click to switch to another profile" msgstr "Klikněte pro přepnutí na jiný profil" #: data/ui/MousePerspective.ui:185 msgid "Add profile" msgstr "Přidat profil" #: data/ui/MousePerspective.ui:189 msgid "Add a new profile to the device" msgstr "Přidá nový profil do zařízení" #: data/ui/OptionButton.ui:9 msgid "Open the configuration dialog" msgstr "Otevře konfigurační dialog" #: data/ui/ProfileRow.ui:16 msgid "Remove this profile from the device" msgstr "Smaže tento profil ze zařízení" #. Translators: this is used to indicate the active resolution. #: data/ui/ResolutionRow.ui:37 msgid "Active" msgstr "Aktivní" #: data/ui/ResolutionRow.ui:77 msgid "Set this resolution’s DPI" msgstr "Nastaví DPI tohoto rozlišení" #. Translators: the rate at which the device reports movement. #: data/ui/ResolutionsPage.ui:43 msgid "Report rate" msgstr "Rychlost hlášení" #: data/ui/ResolutionsPage.ui:60 msgid "Change the profile’s report rate" msgstr "Změní rychlost hlášení profilu" #: data/ui/ResolutionsPage.ui:136 msgid "Hz" msgstr "Hz" #. Translators: the sensitivity of the device's sensor. #: data/ui/ResolutionsPage.ui:156 msgid "Sensitivity" msgstr "Citlivost" #: data/ui/ResolutionsPage.ui:205 msgid "Add a new resolution to the profile" msgstr "Přidá nové rozlišení do profilu" #: data/ui/WelcomePerspective.ui:20 msgid "Welcome" msgstr "Vítejte" #: data/ui/WelcomePerspective.ui:38 msgctxt "A subtitle under the \"Welcome\" title." msgid "Select a device to configure it" msgstr "Vyberte zařízení pro konfiguraci" #: data/ui/WelcomePerspective.ui:89 msgctxt "A tooltip over the list of devices." msgid "Select a device to configure it" msgstr "Vybere zařízení pro konfiguraci" #: data/ui/WelcomePerspective.ui:119 msgid "Select a Device" msgstr "Vyberte zařízení" #: data/ui/Window.ui:8 msgid "_About Piper" msgstr "_O Piperu" piper-0.8/po/de.po000066400000000000000000000364551467456234500141030ustar00rootroot00000000000000# GermanPiper translation # Copyright (C) 2017 Red Hat, Inc. # This file is distributed under the same license as the piper package. # Peter Hutterer , 2017. # msgid "" msgstr "" "Project-Id-Version: piper\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2020-01-28 20:40+0100\n" "PO-Revision-Date: 2017-08-23 13:02+1000\n" "Last-Translator: Nicolai Weitkemper \n" "Language-Team: German <>\n" "Language: de\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: data/org.freedesktop.Piper.desktop.in:3 #: data/org.freedesktop.Piper.appdata.xml.in.in:7 msgid "Piper" msgstr "Piper" #: data/org.freedesktop.Piper.desktop.in:4 #: data/org.freedesktop.Piper.appdata.xml.in.in:8 msgid "Configurable mouse configuration utility" msgstr "Konfigurationsprogramm für konfigurierbare Mäuse" #. Translators: Do NOT translate or transliterate this text (this is an icon file name)! #: data/org.freedesktop.Piper.desktop.in:7 msgid "org.freedesktop.Piper" msgstr "org.freedesktop.Piper" #. Translators: Search terms to find this application. Do NOT translate or localize the semicolons! The list MUST also end with a semicolon! #: data/org.freedesktop.Piper.desktop.in:12 msgid "gaming;configuration;mouse;mice;" msgstr "Spiele;Games;Konfiguration;Maus;Mäuse;" #: data/org.freedesktop.Piper.appdata.xml.in.in:10 msgid "" "Piper is a graphical user interface to configure gaming mice. Configuration " "options include changing the resolution (DPI) of the mouse, adding and " "removing profiles, setting LED colors and changing button behaviors." msgstr "" "Piper ist eine grafische Benutzeroberfläche zur Konfiguration von Gaming-" "Mäusen. Mögliche Konfigurationsoptionen sind die Auflösung der Maus (DPI), " "das Editieren von Profilen, LED-Farbeinstellungen und der Tastenzuweisung." #: data/org.freedesktop.Piper.appdata.xml.in.in:16 msgid "" "Piper requires libratbag’s ratbagd, the daemon to actually communicate with " "the mice. Piper is merely a front end to ratbagd, ratbagd must be installed " "and running when Piper is launched." msgstr "" "Piper benötigt libratbag's ratbagd, den Daemon, der die eigentliche " "Kommunikation mit der Maus verwaltet. Piper ist nur eine grafische " "Benutzeroberfläche für ratbagd; ratbagd muss installiert sein und laufen, " "wenn Piper gestartet wird." #: data/org.freedesktop.Piper.appdata.xml.in.in:33 #, fuzzy msgid "The button configuraton page" msgstr "Das Konfigurationsfenster öffnen" #: data/org.freedesktop.Piper.appdata.xml.in.in:37 #, fuzzy msgid "The LED configuraton page" msgstr "Das Konfigurationsfenster öffnen" #: data/org.freedesktop.Piper.appdata.xml.in.in:41 #, fuzzy msgid "The resolution configuraton page" msgstr "Das Konfigurationsfenster öffnen" #. Translators: section header for mapping one button's click to another. #: piper/buttondialog.py:141 msgid "Button mapping" msgstr "Tastenfunktion" #. Translators: section header for assigning special functions to buttons. #: piper/buttondialog.py:150 msgid "Special mapping" msgstr "Spezialfunktion" #. Translators: the {} will be replaced with the button index, e.g. #. "Button 1 click". #: piper/buttondialog.py:222 piper/buttonspage.py:90 msgid "Button {} click" msgstr "Klick mit Taste {}" #: piper/buttonspage.py:94 msgid "Macro: {}" msgstr "Makro: {}" #. Translators: the button is turned disabled, e.g. off. #: piper/buttonspage.py:97 msgid "Disabled" msgstr "Abgeschaltet" #. Translators: the button has an unknown function. #: piper/buttonspage.py:100 piper/ratbagd.py:665 msgid "Unknown" msgstr "Unbekannt" #: piper/buttonspage.py:108 msgid "Configure button {}" msgstr "Taste {} konfigurieren" #: piper/mouseperspective.py:90 data/ui/ResolutionsPage.ui:209 msgid "Resolutions" msgstr "Auflösungen" #: piper/mouseperspective.py:92 msgid "Buttons" msgstr "Tasten" #: piper/mouseperspective.py:94 msgid "LEDs" msgstr "LEDs" #: piper/ratbagd.py:655 msgid "Left mouse button click" msgstr "Klick mit linker Maustaste" #: piper/ratbagd.py:656 msgid "Right mouse button click" msgstr "Klick mit rechter Maustaste" #: piper/ratbagd.py:657 msgid "Middle mouse button click" msgstr "Klick mit mittlerer Maustaste" #: piper/ratbagd.py:658 msgid "Backward" msgstr "Zurück" #: piper/ratbagd.py:659 msgid "Forward" msgstr "Weiter" #: piper/ratbagd.py:664 msgid "Invalid" msgstr "Ungültig" #: piper/ratbagd.py:666 msgid "Doubleclick" msgstr "Doppelklick" #: piper/ratbagd.py:667 msgid "Wheel Left" msgstr "Mausrad links" #: piper/ratbagd.py:668 msgid "Wheel Right" msgstr "Mausrad rechts" #: piper/ratbagd.py:669 msgid "Wheel Up" msgstr "Mausrad hinauf" #: piper/ratbagd.py:670 msgid "Wheel Down" msgstr "Mausrad hinunter" #: piper/ratbagd.py:671 msgid "Ratchet Mode" msgstr "Präzisionsmodus" #: piper/ratbagd.py:672 msgid "Cycle Resolution Up" msgstr "Nächste Auflösung (zyklisch)" #: piper/ratbagd.py:673 msgid "Cycle Resolution Down" msgstr "Vorherige Auflösung (zyklisch)" #: piper/ratbagd.py:674 msgid "Resolution Up" msgstr "Nächste Auflösung" #: piper/ratbagd.py:675 msgid "Resolution Down" msgstr "Vorherige Auflösung" #: piper/ratbagd.py:676 msgid "Resolution Switch" msgstr "Auflösung wechseln" #: piper/ratbagd.py:677 msgid "Default Resolution" msgstr "Standardauflösung" #: piper/ratbagd.py:678 msgid "Cycle Profile Up" msgstr "Nächstes Profil (zyklisch)" #: piper/ratbagd.py:679 msgid "Cycle Profile Down" msgstr "Vorheriges Profil (zyklisch)" #: piper/ratbagd.py:680 msgid "Profile Up" msgstr "Nächstes Profil" #: piper/ratbagd.py:681 msgid "Profile Down" msgstr "Vorheriges Profil" #: piper/ratbagd.py:682 msgid "Second Mode" msgstr "Zweiter Modus" #: piper/ratbagd.py:683 msgid "Battery Level" msgstr "Batterieladestand" #. Translators: this is used when there is no macro to preview. #: piper/ratbagd.py:813 data/ui/ButtonDialog.ui:106 data/ui/ButtonDialog.ui:187 msgid "None" msgstr "Nicht zugewiesen" #. Translators: the LED is off. #: piper/ratbagd.py:895 data/ui/LedDialog.ui:395 msgid "Off" msgstr "Aus" #. Translators: the LED has a single, solid color. #: piper/ratbagd.py:897 data/ui/LedDialog.ui:66 msgid "Solid" msgstr "Dauerhaft" #. Translators: the LED is cycling between red, green and blue. #: piper/ratbagd.py:899 data/ui/LedDialog.ui:189 msgid "Cycle" msgstr "Zyklus" #. Translators: the LED's is pulsating a single color on different #. brightnesses. #: piper/ratbagd.py:902 data/ui/LedDialog.ui:355 msgid "Breathing" msgstr "Pulsierend" #: piper/window.py:54 msgid "Cannot connect to ratbagd" msgstr "Verbindung mit ratbagd fehlgeschlagen" #: piper/window.py:55 #, fuzzy msgid "" "Please make sure ratbagd is running and your user is in the required group" msgstr "" "Bitte vergewissern Sie sich, dass ratbagd läuft und der Benutzer in der " "benötigten Gruppe ist" #: piper/window.py:58 msgid "Incompatible ratbagd API version (required: {}, provided: {})" msgstr "Inkompatible API version zu ratbagd (notwendig: {}, aktuell: {})" #: piper/window.py:59 #, fuzzy msgid "Please update both piper and libratbag to the latest versions" msgstr "Bitte sowohl piper als auch libratbag auf die neueste Version updaten." #: piper/window.py:73 piper/window.py:127 msgid "Cannot find any devices" msgstr "Es wurden keine Geräte gefunden" #: piper/window.py:74 piper/window.py:128 msgid "Please make sure your device is supported and plugged in" msgstr "" "Bitte vergewissern Sie sich, dass Ihr Gerät angeschlossen ist und unterstützt " "wird" #: piper/window.py:86 msgid "There are unapplied changes. Are you sure you want to quit?" msgstr "Es gibt ungespeicherte Änderungen. Wollen Sie wirklich beenden?" #: piper/window.py:95 msgid "Ooops. ratbagd has disappeared" msgstr "Ups. ratbagd hat sich in Luft aufgelöst" #: piper/window.py:96 msgid "Please restart Piper" msgstr "Bitte starten Sie Piper neu" #. The current device disconnected, which can only happen from the #. mouse perspective as we'd otherwise be in the welcome screen with #. more than one device remaining. Hence, we display the error #. perspective. #: piper/window.py:119 msgid "Your device disconnected!" msgstr "Das Gerät wurde entfernt!" #: piper/window.py:120 msgid "Please make sure your device is plugged in" msgstr "Bitte vergewissern Sie sich, dass Ihr Gerät angeschlossen ist" #: piper/window.py:159 msgid "Cannot display device SVG" msgstr "Das SVG des Gerätes kann nicht angezeigt werden" #: piper/window.py:166 msgid "Newer version of ratbagd required" msgstr "Eine neuere Version von ratbagd ist notwendig" #: piper/window.py:167 msgid "Please update to the latest available version" msgstr "Bitte auf die neueste Version updaten." #: piper/window.py:169 msgid "Unknown exception occurred" msgstr "Ein unbekannter Fehler ist aufgetreten" #: data/ui/AboutDialog.ui.in:10 msgid "Version: @version@" msgstr "Version: @version@" #: data/ui/AboutDialog.ui.in:12 #, fuzzy msgid "Visit Piper on GitHub" msgstr "Besuche Piper auf GitHub" #: data/ui/AboutDialog.ui.in:13 msgid "translator-credits" msgstr "Peter Hutterer , 2017-2019" "\nNicolai Weitkemper , 2020" #: data/ui/ButtonDialog.ui:65 msgid "Search for a button mapping" msgstr "Eine Tastenfunktion suchen" #: data/ui/ButtonDialog.ui:91 msgid "Capture a macro for this button" msgstr "Ein Makro für diese Taste aufnehmen" #: data/ui/ButtonDialog.ui:104 msgid "The currently set macro" msgstr "Das aktuelle Makro" #: data/ui/ButtonDialog.ui:129 msgid "Send keystroke" msgstr "Tastenkombination eingeben" #: data/ui/ButtonDialog.ui:169 msgid "Enter a new key sequence for the macro." msgstr "Bitte geben Sie eine neue Tastenkombination für das Makro ein" #: data/ui/ButtonDialog.ui:221 msgid "Press Escape to cancel or Return to accept." msgstr "Drücken Sie Escape um abzubrechen oder Enter um zu akzeptieren" #: data/ui/ButtonDialog.ui:252 #, fuzzy msgid "Set the device’s handedness." msgstr "Gerät für Links- order Rechtshänder einstellen" #: data/ui/ButtonDialog.ui:270 msgid "" "This allows you to swap the order of the primary mouse buttons. In left-" "handed mode, the physical left mouse button generates a right mouse click " "and vice versa." msgstr "" "Ändern Sie die Funktion der primären Maustasten. Im Linkshändermodus sendet " "die linke Maustaste einen Klick für die rechte Maustaste und umgekehrt." #: data/ui/ButtonDialog.ui:290 msgid "Left Handed" msgstr "Linkshändig" #: data/ui/ButtonDialog.ui:295 msgid "The left mouse button generates a left mouse click" msgstr "Die linke Maustaste sendet einen Klick der linken Taste" #: data/ui/ButtonDialog.ui:309 msgid "Right Handed" msgstr "Rechtshändig" #: data/ui/ButtonDialog.ui:314 msgid "The left mouse button generates a right mouse click" msgstr "Die linke Maustaste sendet einen Klick der rechten Taste" #: data/ui/ButtonDialog.ui:354 data/ui/LedDialog.ui:414 msgid "Cancel" msgstr "Abbrechen" #: data/ui/ButtonDialog.ui:356 data/ui/LedDialog.ui:418 msgid "Ignore any changes made" msgstr "Alle Änderungen verwerfen" #: data/ui/ButtonDialog.ui:362 data/ui/LedDialog.ui:430 #: data/ui/MousePerspective.ui:132 msgid "Apply" msgstr "Zuweisen" #: data/ui/ButtonDialog.ui:365 data/ui/LedDialog.ui:435 msgid "Apply any changes made" msgstr "Alle Änderungen zuweisen" #: data/ui/ButtonDialog.ui:405 msgid "No button mapping found" msgstr "Keine Tastenfunktion gefunden" #: data/ui/ButtonDialog.ui:421 msgid "Try a different search" msgstr "Versuchen Sie eine andere Suche" #: data/ui/ErrorPerspective.ui:16 #, fuzzy msgid "Here, rodent, rodent, rodent…" msgstr "Ja wo bist du denn, kleines Nagetier?" #: data/ui/ErrorPerspective.ui:69 #, fuzzy msgid "Uh Oh! Something went wrong…" msgstr "Ups. Da ist etwas falschgelaufen..." #: data/ui/ErrorPerspective.ui:73 data/ui/WelcomePerspective.ui:123 msgid "Quit" msgstr "Beenden" #: data/ui/LedDialog.ui:58 data/ui/LedDialog.ui:209 msgid "Choose a color for the LED" msgstr "Eine Farbe für die LED auswählen" #: data/ui/LedDialog.ui:90 data/ui/LedDialog.ui:257 msgid "Choose a brightness for the LED" msgstr "Helligkeit für die LED auswählen" #: data/ui/LedDialog.ui:104 data/ui/LedDialog.ui:270 msgid "Brightness" msgstr "Helligkeit" #: data/ui/LedDialog.ui:135 data/ui/LedDialog.ui:301 #, fuzzy msgid "Choose an effect duration for the LED" msgstr "Effektrate für die LED auswählen" #: data/ui/LedDialog.ui:153 data/ui/LedDialog.ui:319 msgid "ms" msgstr "ms" #: data/ui/LedDialog.ui:175 data/ui/LedDialog.ui:341 #, fuzzy msgid "Effect duration" msgstr "Effektrate" #: data/ui/LedDialog.ui:212 msgid "Pick a Color for the LED" msgstr "Eine Farbe für die LED auswählen" #: data/ui/LedDialog.ui:226 msgid "Color" msgstr "Farbe" #: data/ui/LedDialog.ui:380 msgid "This LED is off" msgstr "Diese LED ist ausgeschaltet" #: data/ui/MousePerspective.ui:44 msgid "Something went wrong. The device has been reset to a previous state." msgstr "" "Irgendetwas ist falschgelaufen. Das Gerät wurde auf einen vorherigen Stand " "zurückgesetzt." #: data/ui/MousePerspective.ui:101 msgid "Select another profile" msgstr "Anderes Profile auswählen" #: data/ui/MousePerspective.ui:126 msgid "Commit the changes to the device" msgstr "Änderungen auf das Gerät übertragen" #: data/ui/MousePerspective.ui:170 msgid "Click to switch to another profile" msgstr "Klicken Sie hier, um auf ein anderes Profil zu wechseln" #: data/ui/MousePerspective.ui:185 msgid "Add profile" msgstr "Profil hinzufügen" #: data/ui/MousePerspective.ui:189 msgid "Add a new profile to the device" msgstr "Profil hinzufügen" #: data/ui/OptionButton.ui:9 msgid "Open the configuration dialog" msgstr "Das Konfigurationsfenster öffnen" #: data/ui/ProfileRow.ui:16 msgid "Remove this profile from the device" msgstr "Dieses Profil vom Gerät löschen" #. Translators: this is used to indicate the active resolution. #: data/ui/ResolutionRow.ui:37 msgid "Active" msgstr "Aktiv" #: data/ui/ResolutionRow.ui:77 #, fuzzy msgid "Set this resolution’s DPI" msgstr "Die Auflösung einstellen (in DPI)" #. Translators: the rate at which the device reports movement. #: data/ui/ResolutionsPage.ui:43 msgid "Report rate" msgstr "Abtastrate" #: data/ui/ResolutionsPage.ui:60 #, fuzzy msgid "Change the profile’s report rate" msgstr "Die Abtastrate für dieses Profil einstellen" #: data/ui/ResolutionsPage.ui:105 msgid "Hz" msgstr "Hz" #. Translators: the sensitivity of the device's sensor. #: data/ui/ResolutionsPage.ui:125 msgid "Sensitivity" msgstr "Auflösung" #: data/ui/ResolutionsPage.ui:174 msgid "Add a new resolution to the profile" msgstr "Eine neue Auflösung zum Profil hinzufügen" #: data/ui/WelcomePerspective.ui:20 msgid "Welcome" msgstr "Willkommen" #: data/ui/WelcomePerspective.ui:38 msgctxt "A subtitle under the \"Welcome\" title." msgid "Select a device to configure it" msgstr "Bitte ein Gerät zur Konfiguration auswählen" #: data/ui/WelcomePerspective.ui:89 msgctxt "A tooltip over the list of devices." msgid "Select a device to configure it" msgstr "Bitte ein Gerät zur Konfiguration auswählen" #: data/ui/WelcomePerspective.ui:119 msgid "Select a Device" msgstr "Bitte ein Gerät auswählen" #: data/ui/Window.ui:8 #, fuzzy msgid "_About Piper" msgstr "_Info" #~ msgid "Remove this resolution from the profile" #~ msgstr "Diese Auflösung vom Gerät löschen" #~ msgid "_Quit" #~ msgstr "_Beenden" #~ msgid "Failed to commit changes to the device" #~ msgstr "Das Speichern der Änderungen ist fehlgeschlagen" #~ msgid "Profile {}" #~ msgstr "Profil {}" piper-0.8/po/es.po000066400000000000000000000357161467456234500141210ustar00rootroot00000000000000# Spanish translation of Piper # Copyright (C) 2019 Piper Developers # This file is distributed under the same license as the piper package. # Amaro Martínez , 2019, 2020. # msgid "" msgstr "" "Project-Id-Version: piper\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2020-03-14 15:13-0500\n" "PO-Revision-Date: 2020-03-14 15:37-0500\n" "Last-Translator: Amaro Martínez \n" "Language-Team: Español; Castellano <>\n" "Language: es\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: Gtranslator 2.91.7\n" #: data/org.freedesktop.Piper.desktop.in:3 #: data/org.freedesktop.Piper.appdata.xml.in.in:7 msgid "Piper" msgstr "Piper" #: data/org.freedesktop.Piper.desktop.in:4 #: data/org.freedesktop.Piper.appdata.xml.in.in:8 msgid "Configurable mouse configuration utility" msgstr "Utilidad de configuración de ratón configurable" #. Translators: Do NOT translate or transliterate this text (this is an icon file name)! #: data/org.freedesktop.Piper.desktop.in:7 msgid "org.freedesktop.Piper" msgstr "org.freedesktop.Piper" #. Translators: Search terms to find this application. Do NOT translate or localize the semicolons! The list MUST also end with a semicolon! #: data/org.freedesktop.Piper.desktop.in:12 msgid "gaming;configuration;mouse;mice;" msgstr "gaming;configuración;ratón;ratones;" #: data/org.freedesktop.Piper.appdata.xml.in.in:10 msgid "" "Piper is a graphical user interface to configure gaming mice. Configuration " "options include changing the resolution (DPI) of the mouse, adding and " "removing profiles, setting LED colors and changing button behaviors." msgstr "" "Piper es una interfaz gráfica de usuario para configurar ratones «gaming». " "Las opciones de configuración incluyen cambiar la resolución PPP (DPI) del " "ratón, añadir y eliminar perfiles, configurar los colores de los LED y " "cambiar el comportamiento de los botones." #: data/org.freedesktop.Piper.appdata.xml.in.in:16 msgid "" "Piper requires libratbag’s ratbagd, the daemon to actually communicate with " "the mice. Piper is merely a front end to ratbagd, ratbagd must be installed " "and running when Piper is launched." msgstr "" "Piper necesita ratbagd de libratbag, el demonio, para poder comunicarse con " "los ratones. Piper es simplemente un frontal para ratbagd, ratbagd debe " "estar instalado y funcionando cuando inicie Piper." #: data/org.freedesktop.Piper.appdata.xml.in.in:33 msgid "The button configuraton page" msgstr "La página de configuración de botones" #: data/org.freedesktop.Piper.appdata.xml.in.in:37 msgid "The LED configuraton page" msgstr "La página de configuración de LEDs" #: data/org.freedesktop.Piper.appdata.xml.in.in:41 msgid "The resolution configuraton page" msgstr "La página de configuración de resolución" #. Translators: section header for mapping one button's click to another. #: piper/buttondialog.py:141 msgid "Button mapping" msgstr "Mapeado de botones" #. Translators: section header for assigning special functions to buttons. #: piper/buttondialog.py:150 msgid "Special mapping" msgstr "Mapeado especial" #. Translators: the {} will be replaced with the button index, e.g. #. "Button 1 click". #: piper/buttondialog.py:222 piper/buttonspage.py:90 msgid "Button {} click" msgstr "Pulsación del botón {}" #: piper/buttonspage.py:94 msgid "Macro: {}" msgstr "Macro: {}" #. Translators: the button is turned disabled, e.g. off. #: piper/buttonspage.py:97 msgid "Disabled" msgstr "Desactivado" #. Translators: the button has an unknown function. #: piper/buttonspage.py:100 piper/ratbagd.py:665 msgid "Unknown" msgstr "Desconocido" #: piper/buttonspage.py:108 msgid "Configure button {}" msgstr "Configurar botón {}" #: piper/mouseperspective.py:90 data/ui/ResolutionsPage.ui:209 msgid "Resolutions" msgstr "Resoluciones" #: piper/mouseperspective.py:92 msgid "Buttons" msgstr "Botones" #: piper/mouseperspective.py:94 msgid "LEDs" msgstr "LEDs" #: piper/ratbagd.py:655 msgid "Left mouse button click" msgstr "Pulsación del botón primario del ratón" #: piper/ratbagd.py:656 msgid "Right mouse button click" msgstr "Pulsación del botón secundario del ratón" #: piper/ratbagd.py:657 msgid "Middle mouse button click" msgstr "Pulsación del botón central del ratón" #: piper/ratbagd.py:658 msgid "Backward" msgstr "Atrás" #: piper/ratbagd.py:659 msgid "Forward" msgstr "Adelante" #: piper/ratbagd.py:664 msgid "Invalid" msgstr "No válida" #: piper/ratbagd.py:666 msgid "Doubleclick" msgstr "Doble pulsación" #: piper/ratbagd.py:667 msgid "Wheel Left" msgstr "Rueda a la izquierda" #: piper/ratbagd.py:668 msgid "Wheel Right" msgstr "Rueda a la derecha" #: piper/ratbagd.py:669 msgid "Wheel Up" msgstr "Rueda hacia arriba" #: piper/ratbagd.py:670 msgid "Wheel Down" msgstr "Rueda hacia abajo" #: piper/ratbagd.py:671 msgid "Ratchet Mode" msgstr "Modo de giro gradual" #: piper/ratbagd.py:672 msgid "Cycle Resolution Up" msgstr "Ciclo de resolución siguiente" #: piper/ratbagd.py:673 msgid "Cycle Resolution Down" msgstr "Ciclo de resolución anterior" #: piper/ratbagd.py:674 msgid "Resolution Up" msgstr "Aumentar resolución" #: piper/ratbagd.py:675 msgid "Resolution Down" msgstr "Reducir resolución" #: piper/ratbagd.py:676 msgid "Resolution Switch" msgstr "Cambiar resolución" #: piper/ratbagd.py:677 msgid "Default Resolution" msgstr "Resolución predeterminada" #: piper/ratbagd.py:678 msgid "Cycle Profile Up" msgstr "Ciclo de perfil siguiente" #: piper/ratbagd.py:679 msgid "Cycle Profile Down" msgstr "Ciclo de perfil anterior" #: piper/ratbagd.py:680 msgid "Profile Up" msgstr "Perfil siguiente" #: piper/ratbagd.py:681 msgid "Profile Down" msgstr "Perfil anterior" #: piper/ratbagd.py:682 msgid "Second Mode" msgstr "Segundo modo" #: piper/ratbagd.py:683 msgid "Battery Level" msgstr "Nivel de la batería" #. Translators: this is used when there is no macro to preview. #: piper/ratbagd.py:813 data/ui/ButtonDialog.ui:106 data/ui/ButtonDialog.ui:187 msgid "None" msgstr "Ninguno" #. Translators: the LED is off. #: piper/ratbagd.py:895 data/ui/LedDialog.ui:395 msgid "Off" msgstr "Apagado" #. Translators: the LED has a single, solid color. #: piper/ratbagd.py:897 data/ui/LedDialog.ui:66 msgid "Solid" msgstr "Sólido" #. Translators: the LED is cycling between red, green and blue. #: piper/ratbagd.py:899 data/ui/LedDialog.ui:189 msgid "Cycle" msgstr "Ciclo" #. Translators: the LED's is pulsating a single color on different #. brightnesses. #: piper/ratbagd.py:902 data/ui/LedDialog.ui:355 msgid "Breathing" msgstr "Respiración" #: piper/window.py:54 msgid "Cannot connect to ratbagd" msgstr "No se puede conectar a ratbagd" #: piper/window.py:55 msgid "" "Please make sure ratbagd is running and your user is in the required group" msgstr "" "Asegúrese de que ratbagd se esté ejecutando y que su usuario esté en el " "grupo requerido" #: piper/window.py:58 msgid "Incompatible ratbagd API version (required: {}, provided: {})" msgstr "" "Versión de la API ratbagd incompatible (necesaria: {}, proporcionada: {})" #: piper/window.py:59 msgid "Please update both piper and libratbag to the latest versions" msgstr "Actualice tanto piper como libratbag a las últimas versiones" #: piper/window.py:73 piper/window.py:127 msgid "Cannot find any devices" msgstr "No se puede encontrar ningún dispositivo" #: piper/window.py:74 piper/window.py:128 msgid "Please make sure your device is supported and plugged in" msgstr "Asegúrese de que su dispositivo es compatible y está conectado" #: piper/window.py:86 msgid "There are unapplied changes. Are you sure you want to quit?" msgstr "Hay cambios no aplicados. ¿Seguro que quiere salir?" #: piper/window.py:95 msgid "Ooops. ratbagd has disappeared" msgstr "Vaya. ratbagd ha desaparecido" #: piper/window.py:96 msgid "Please restart Piper" msgstr "Reinicie Piper" #. The current device disconnected, which can only happen from the #. mouse perspective as we'd otherwise be in the welcome screen with #. more than one device remaining. Hence, we display the error #. perspective. #: piper/window.py:119 msgid "Your device disconnected!" msgstr "¡Su dispositivo está desconectado!" #: piper/window.py:120 msgid "Please make sure your device is plugged in" msgstr "Asegúrese de que su dispositivo está conectado" #: piper/window.py:159 msgid "Cannot display device SVG" msgstr "No se puede mostrar el SVG del dispositivo" #: piper/window.py:166 msgid "Newer version of ratbagd required" msgstr "Se requiere una versión más reciente de ratbagd" #: piper/window.py:167 msgid "Please update to the latest available version" msgstr "Actualice a la última versión disponible" #: piper/window.py:169 msgid "Unknown exception occurred" msgstr "Ha ocurrido una excepción desconocida" #: data/ui/AboutDialog.ui.in:10 msgid "Version: @version@" msgstr "Versión: @version@" #: data/ui/AboutDialog.ui.in:12 msgid "Visit Piper on GitHub" msgstr "Visitar Piper en GitHub" #: data/ui/AboutDialog.ui.in:13 msgid "translator-credits" msgstr "Amaro Martínez , 2019, 2020" #: data/ui/ButtonDialog.ui:65 msgid "Search for a button mapping" msgstr "Buscar un mapeado de botón" #: data/ui/ButtonDialog.ui:91 msgid "Capture a macro for this button" msgstr "Capturar una macro para este botón" #: data/ui/ButtonDialog.ui:104 msgid "The currently set macro" msgstr "La macro actualmente establecida" #: data/ui/ButtonDialog.ui:129 msgid "Send keystroke" msgstr "Enviar pulsación de teclas" #: data/ui/ButtonDialog.ui:169 msgid "Enter a new key sequence for the macro." msgstr "Introduzca una combinación de teclas nueva para la macro." #: data/ui/ButtonDialog.ui:221 msgid "Press Escape to cancel or Return to accept." msgstr "Pulse Esc para cancelar o Intro para aceptar." #: data/ui/ButtonDialog.ui:252 msgid "Set the device’s handedness." msgstr "Establezca la mano dominante del dispositivo." #: data/ui/ButtonDialog.ui:270 msgid "" "This allows you to swap the order of the primary mouse buttons. In left-" "handed mode, the physical left mouse button generates a right mouse click " "and vice versa." msgstr "" "Esto le permite cambiar el orden de los botones principales del ratón. En " "modo zurdo, el botón primario físico del ratón genera una pulsación " "secundaria del ratón y viceversa." #: data/ui/ButtonDialog.ui:290 msgid "Left Handed" msgstr "Zurdo" #: data/ui/ButtonDialog.ui:295 msgid "The left mouse button generates a left mouse click" msgstr "El botón primario del ratón genera una pulsación primaria del ratón" #: data/ui/ButtonDialog.ui:309 msgid "Right Handed" msgstr "Diestro" #: data/ui/ButtonDialog.ui:314 msgid "The left mouse button generates a right mouse click" msgstr "El botón primario del ratón genera una pulsación secundaria del ratón" #: data/ui/ButtonDialog.ui:354 data/ui/LedDialog.ui:414 msgid "Cancel" msgstr "Cancelar" #: data/ui/ButtonDialog.ui:356 data/ui/LedDialog.ui:418 msgid "Ignore any changes made" msgstr "Ignorar los cambios realizados" #: data/ui/ButtonDialog.ui:362 data/ui/LedDialog.ui:430 #: data/ui/MousePerspective.ui:132 msgid "Apply" msgstr "Aplicar" #: data/ui/ButtonDialog.ui:365 data/ui/LedDialog.ui:435 msgid "Apply any changes made" msgstr "Aplicar los cambios realizados" #: data/ui/ButtonDialog.ui:405 msgid "No button mapping found" msgstr "No se ha encontrado ningún mapeado de botón" #: data/ui/ButtonDialog.ui:421 msgid "Try a different search" msgstr "Pruebe a hacer una búsqueda diferente" #: data/ui/ErrorPerspective.ui:16 msgid "Here, rodent, rodent, rodent…" msgstr "Aquí, roedor, roedor, roedor…" #: data/ui/ErrorPerspective.ui:69 msgid "Uh Oh! Something went wrong…" msgstr "Algo ha fallado…" #: data/ui/ErrorPerspective.ui:73 data/ui/WelcomePerspective.ui:123 msgid "Quit" msgstr "Salir" #: data/ui/LedDialog.ui:58 data/ui/LedDialog.ui:209 msgid "Choose a color for the LED" msgstr "Elija un color para el LED" #: data/ui/LedDialog.ui:90 data/ui/LedDialog.ui:257 msgid "Choose a brightness for the LED" msgstr "Elija un brillo para el LED" #: data/ui/LedDialog.ui:104 data/ui/LedDialog.ui:270 msgid "Brightness" msgstr "Brillo" #: data/ui/LedDialog.ui:135 data/ui/LedDialog.ui:301 msgid "Choose an effect duration for the LED" msgstr "Elija una duración de efecto para el LED" #: data/ui/LedDialog.ui:153 data/ui/LedDialog.ui:319 msgid "ms" msgstr "ms" #: data/ui/LedDialog.ui:175 data/ui/LedDialog.ui:341 msgid "Effect duration" msgstr "Duración del efecto" #: data/ui/LedDialog.ui:212 msgid "Pick a Color for the LED" msgstr "Elegir un color para el LED" #: data/ui/LedDialog.ui:226 msgid "Color" msgstr "Color" #: data/ui/LedDialog.ui:380 msgid "This LED is off" msgstr "Este LED está apagado" #: data/ui/MousePerspective.ui:44 msgid "Something went wrong. The device has been reset to a previous state." msgstr "" "Algo salió mal. El dispositivo se ha restablecido a un estado anterior." #: data/ui/MousePerspective.ui:101 msgid "Select another profile" msgstr "Seleccione otro perfil" #: data/ui/MousePerspective.ui:126 msgid "Commit the changes to the device" msgstr "Efectuar los cambios en el dispositivo" #: data/ui/MousePerspective.ui:170 msgid "Click to switch to another profile" msgstr "Pulse para cambiar a otro perfil" #: data/ui/MousePerspective.ui:185 msgid "Add profile" msgstr "Añadir perfil" #: data/ui/MousePerspective.ui:189 msgid "Add a new profile to the device" msgstr "Añadir un nuevo perfil al dispositivo" #: data/ui/OptionButton.ui:9 msgid "Open the configuration dialog" msgstr "Abre el diálogo de configuración" #: data/ui/ProfileRow.ui:16 msgid "Remove this profile from the device" msgstr "Quite este perfil del dispositivo" #. Translators: this is used to indicate the active resolution. #: data/ui/ResolutionRow.ui:37 msgid "Active" msgstr "Activo" #: data/ui/ResolutionRow.ui:77 msgid "Set this resolution’s DPI" msgstr "Establezca el DPI de esta resolución" #. Translators: the rate at which the device reports movement. #: data/ui/ResolutionsPage.ui:43 msgid "Report rate" msgstr "Velocidad de respuesta" #: data/ui/ResolutionsPage.ui:60 msgid "Change the profile’s report rate" msgstr "Cambia la velocidad de respuesta del perfil" #: data/ui/ResolutionsPage.ui:105 msgid "Hz" msgstr "Hz" #. Translators: the sensitivity of the device's sensor. #: data/ui/ResolutionsPage.ui:125 msgid "Sensitivity" msgstr "Sensibilidad" #: data/ui/ResolutionsPage.ui:174 msgid "Add a new resolution to the profile" msgstr "Añadir una nueva resolución al perfil" #: data/ui/WelcomePerspective.ui:20 msgid "Welcome" msgstr "Bienvenido" #: data/ui/WelcomePerspective.ui:38 msgctxt "A subtitle under the \"Welcome\" title." msgid "Select a device to configure it" msgstr "Seleccionar un dispositivo para configurarlo" #: data/ui/WelcomePerspective.ui:89 msgctxt "A tooltip over the list of devices." msgid "Select a device to configure it" msgstr "Seleccione un dispositivo para configurarlo" #: data/ui/WelcomePerspective.ui:119 msgid "Select a Device" msgstr "Seleccione un dispositivo" #: data/ui/Window.ui:8 msgid "_About Piper" msgstr "_Acerca de Piper" piper-0.8/po/fr.po000066400000000000000000000354471467456234500141220ustar00rootroot00000000000000# This file is distributed under the same license as the piper package. # msgid "" msgstr "" "Project-Id-Version: piper\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2024-07-03 19:03+0200\n" "PO-Revision-Date: 2024-07-03 20:18+0200\n" "Last-Translator: Vincent Verdier \n" "Language-Team: French <>\n" "Language: fr\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Generator: Poedit 3.2.2\n" #: data/org.freedesktop.Piper.desktop.in:3 #: data/org.freedesktop.Piper.appdata.xml.in.in:7 msgid "Piper" msgstr "Piper" #: data/org.freedesktop.Piper.desktop.in:4 msgid "Configurable mouse configuration utility" msgstr "Outil de configuration de souris programmable" #. Translators: Search terms to find this application. Do NOT translate or localize the semicolons! The list MUST also end with a semicolon! #: data/org.freedesktop.Piper.desktop.in:12 msgid "gaming;configuration;mouse;mice;" msgstr "gaming;configuration;souris;souris;" #: data/org.freedesktop.Piper.appdata.xml.in.in:8 msgid "Gaming mouse configuration utility" msgstr "Outil de configuration de souris gaming" #: data/org.freedesktop.Piper.appdata.xml.in.in:10 msgid "" "Piper is a graphical user interface to configure gaming mice. Configuration " "options include changing the resolution (DPI) of the mouse, adding and " "removing profiles, setting LED colors and changing button behaviors." msgstr "" "Piper est une interface graphique pour configurer votre souris. Les options " "de configuration comprennent changer la resolution (DPI) de la souris, " "ajouter et supprimer des profils, définir la couleurs des LEDs et changer " "le comportement des boutons." #: data/org.freedesktop.Piper.appdata.xml.in.in:16 msgid "" "Piper requires libratbag’s ratbagd, the daemon to actually communicate with " "the mice. Piper is merely a front end to ratbagd, ratbagd must be installed " "and running when Piper is launched." msgstr "" "Piper a besoin de ratbagd, le démon de libratbag qui permet de communiquer " "avec la souris. Piper est seulement une interface à ratbagd, ratbagd doit " "donc être installé et en cours d’exécution quand Piper est lancé." #: data/org.freedesktop.Piper.appdata.xml.in.in:27 msgid "The button configuraton page" msgstr "La page de configuration des boutons" #: data/org.freedesktop.Piper.appdata.xml.in.in:31 msgid "The LED configuraton page" msgstr "La page de configuration des LEDs" #: data/org.freedesktop.Piper.appdata.xml.in.in:35 msgid "The resolution configuraton page" msgstr "La page de configuration de la résolution" #: piper/buttondialog.py:156 msgid "Button mapping" msgstr "Mappage des boutons" #: piper/buttondialog.py:172 msgid "Special mapping" msgstr "Mappage spécial" #: piper/buttondialog.py:182 data/ui/ResolutionRow.ui:95 msgid "Disable" msgstr "Désactiver" #: piper/buttondialog.py:182 msgid "Other" msgstr "Autre" #. Translators: the {} will be replaced with the button index, e.g. #. "Button 1 click". #: piper/buttondialog.py:257 piper/buttonspage.py:105 msgid "Button {} click" msgstr "Clic du bouton {}" #: piper/buttonspage.py:109 msgid "Macro: {}" msgstr "Macro: {}" #: piper/buttonspage.py:111 msgid "Key: {}" msgstr "Touche: {}" #. Translators: the button is turned disabled, e.g. off. #: piper/buttonspage.py:114 msgid "Disabled" msgstr "Désactivé" #. Translators: the button has an unknown function. #: piper/buttonspage.py:117 piper/ratbagd.py:866 msgid "Unknown" msgstr "Inconnue" #: piper/buttonspage.py:131 msgid "Configure button {}" msgstr "Configurer le bouton {}" #: piper/mouseperspective.py:121 data/ui/ResolutionsPage.ui:78 msgid "Resolutions" msgstr "Résolutions" #: piper/mouseperspective.py:125 msgid "Buttons" msgstr "Boutons" #: piper/mouseperspective.py:128 msgid "LEDs" msgstr "LEDs" #: piper/mouseperspective.py:139 msgid "Advanced" msgstr "Avancé" #: piper/ratbagd.py:856 msgid "Left mouse button click" msgstr "Clic gauche" #: piper/ratbagd.py:857 msgid "Right mouse button click" msgstr "Clic droit" #: piper/ratbagd.py:858 msgid "Middle mouse button click" msgstr "Clic milieu" #: piper/ratbagd.py:859 msgid "Backward" msgstr "Précédent" #: piper/ratbagd.py:860 msgid "Forward" msgstr "Suivant" #: piper/ratbagd.py:865 msgid "Invalid" msgstr "Invalide" #: piper/ratbagd.py:867 msgid "Doubleclick" msgstr "Double clic" #: piper/ratbagd.py:868 msgid "Wheel Left" msgstr "Molette Gauche" #: piper/ratbagd.py:869 msgid "Wheel Right" msgstr "Molette Droite" #: piper/ratbagd.py:870 msgid "Wheel Up" msgstr "Molette Haut" #: piper/ratbagd.py:871 msgid "Wheel Down" msgstr "Molette Bas" #: piper/ratbagd.py:872 msgid "Ratchet Mode" msgstr "Mode Précision" #: piper/ratbagd.py:873 msgid "Cycle Resolution Up" msgstr "Cycle la résolution vers le haut" #: piper/ratbagd.py:874 msgid "Cycle Resolution Down" msgstr "Cycle la résolution vers le bas" #: piper/ratbagd.py:875 msgid "Resolution Up" msgstr "Augmente la résolution" #: piper/ratbagd.py:876 msgid "Resolution Down" msgstr "Diminue la résolution" #: piper/ratbagd.py:877 msgid "Resolution Switch" msgstr "Change la résolution" #: piper/ratbagd.py:878 msgid "Default Resolution" msgstr "Résolution par défaut" #: piper/ratbagd.py:879 msgid "Cycle Profile Up" msgstr "Cycle les profils vers le haut" #: piper/ratbagd.py:880 msgid "Cycle Profile Down" msgstr "Cycle les profils vers le bas" #: piper/ratbagd.py:881 msgid "Profile Up" msgstr "Profil suivant" #: piper/ratbagd.py:882 msgid "Profile Down" msgstr "Profil précédent" #: piper/ratbagd.py:883 msgid "Second Mode" msgstr "Second mode" #: piper/ratbagd.py:884 msgid "Battery Level" msgstr "Niveau de batterie" #. Translators: this is used when there is no macro to preview. #: piper/ratbagd.py:1030 data/ui/ButtonDialog.ui:100 #: data/ui/ButtonDialog.ui:181 msgid "None" msgstr "Rien" #. Translators: the LED is off. #: piper/ratbagd.py:1106 data/ui/LedDialog.ui:368 msgid "Off" msgstr "Désactivé" #. Translators: the LED has a single, solid color. #: piper/ratbagd.py:1108 data/ui/LedDialog.ui:59 msgid "Solid" msgstr "Solide" #. Translators: the LED is cycling between red, green and blue. #: piper/ratbagd.py:1110 data/ui/LedDialog.ui:172 msgid "Cycle" msgstr "Cycle" #. Translators: the LED's is pulsating a single color on different #. brightnesses. #: piper/ratbagd.py:1113 data/ui/LedDialog.ui:328 msgid "Breathing" msgstr "Pulsations" #: piper/window.py:48 msgid "Cannot connect to ratbagd" msgstr "Impossible de se connecter à ratbagd" #: piper/window.py:50 msgid "" "Please make sure ratbagd is running and your user is in the required group" msgstr "" "Merci de vérifier que ratbagd est lancé et que l'utilisateur est dans le " "groupe requis" #: piper/window.py:57 #, python-brace-format msgid "" "Incompatible ratbagd API version (required: {e.required_version}, provided: " "{e.ratbagd_version})" msgstr "" "Version de l'API ratbagd incompatible (requise: {e.required_version}, " "présente: {e.ratbagd_version})" #: piper/window.py:59 msgid "Please update both piper and libratbag to the latest versions" msgstr "Merci de mettre à jour piper et libratbag vers leur dernière version" #: piper/window.py:75 piper/window.py:139 msgid "Cannot find any devices" msgstr "Impossible de trouver un périphérique" #: piper/window.py:76 piper/window.py:140 msgid "Please make sure your device is supported and plugged in" msgstr "Merci de vérifier que votre périphérique est supporté et branché" #: piper/window.py:91 msgid "There are unapplied changes. Are you sure you want to quit?" msgstr "" "Les changements ne sont pas appliqués. Voulez-vous quitter quand même ?" #: piper/window.py:102 msgid "Ooops. ratbagd has disappeared" msgstr "Oups. ratbagd a disparu" #: piper/window.py:102 msgid "Please restart Piper" msgstr "Veuillez redémarrer Piper" #: piper/window.py:129 msgid "Your device disconnected!" msgstr "Votre périphérique s'est déconnecté !" #: piper/window.py:130 msgid "Please make sure your device is plugged in" msgstr "Veuillez vérifier que votre périphérique est branché" #: piper/window.py:176 msgid "Cannot display device SVG" msgstr "Le SVG de l'appareil ne peut être affiché" #: piper/window.py:184 msgid "Newer version of ratbagd required" msgstr "Une version plus récente de ratbagd est requise" #: piper/window.py:185 msgid "Please update to the latest available version" msgstr "Merci mettre à jour vers la dernière version" #: piper/window.py:189 msgid "Unknown exception occurred" msgstr "Une erreur inconnue s'est produite" #: data/ui/AboutDialog.ui.in:12 msgid "Visit Piper on GitHub" msgstr "Visitez Piper sur GitHub" #: data/ui/AboutDialog.ui.in:13 msgid "translator-credits" msgstr "" "Mallory Macrez , 2019\n" "Théo Launay , 2020\n" "Vincent Verdier , 2024" #. Translators: the rate at which the device reports movement. #: data/ui/AdvancedPage.ui:33 msgid "Report rate" msgstr "Taux d'interrogation" #: data/ui/AdvancedPage.ui:50 msgid "Change the profile’s report rate" msgstr "Changer le taux d'interrogation de ce profil" #: data/ui/AdvancedPage.ui:125 msgid "Hz" msgstr "Hz" #: data/ui/AdvancedPage.ui:154 msgid "Debounce time" msgstr "Temps d'anti-rebond" #: data/ui/AdvancedPage.ui:183 data/ui/LedDialog.ui:138 #: data/ui/LedDialog.ui:294 msgid "ms" msgstr "ms" #: data/ui/AdvancedPage.ui:212 msgid "Angle snapping" msgstr "Snapping d'angle" #: data/ui/ButtonDialog.ui:59 msgid "Search for a button mapping" msgstr "Chercher un mappage de bouton" #: data/ui/ButtonDialog.ui:85 msgid "Capture a macro for this button" msgstr "Enregistrer une macro pour ce bouton" #: data/ui/ButtonDialog.ui:98 msgid "The currently set macro" msgstr "La macro actuellement définie" #: data/ui/ButtonDialog.ui:123 msgid "Send keystroke" msgstr "Combinaison de touches envoyée" #: data/ui/ButtonDialog.ui:163 msgid "Enter a new key sequence for the macro." msgstr "Entrez une nouvelle séquence de touches pour la macro." #: data/ui/ButtonDialog.ui:229 msgid "Set the device’s handedness." msgstr "Définir pour les droitiers ou les gauchers." #: data/ui/ButtonDialog.ui:247 msgid "" "This allows you to swap the order of the primary mouse buttons. In left-" "handed mode, the physical left mouse button generates a right mouse click " "and vice versa." msgstr "" "Ceci vous permet de changer l'ordre des boutons primaires de la souris. En " "mode gaucher, le bouton physique de gauche génère un clique droit, et " "inversement." #: data/ui/ButtonDialog.ui:267 msgid "Left Handed" msgstr "Gaucher" #: data/ui/ButtonDialog.ui:272 msgid "The left mouse button generates a left mouse click" msgstr "Le bouton gauche génère un clic gauche" #: data/ui/ButtonDialog.ui:286 msgid "Right Handed" msgstr "Droitier" #: data/ui/ButtonDialog.ui:291 msgid "The left mouse button generates a right mouse click" msgstr "Le bouton droit génère un clic droit" #: data/ui/ButtonDialog.ui:331 data/ui/LedDialog.ui:394 msgid "Cancel" msgstr "Annuler" #: data/ui/ButtonDialog.ui:333 data/ui/LedDialog.ui:398 msgid "Ignore any changes made" msgstr "Ignorer les modifications" #: data/ui/ButtonDialog.ui:339 data/ui/LedDialog.ui:403 #: data/ui/MousePerspective.ui:187 msgid "Apply" msgstr "Appliquer" #: data/ui/ButtonDialog.ui:342 data/ui/LedDialog.ui:408 msgid "Apply any changes made" msgstr "Appliquer les modifications" #: data/ui/ButtonDialog.ui:382 msgid "No button mapping found" msgstr "Aucun mappage de bouton trouvé" #: data/ui/ButtonDialog.ui:398 msgid "Try a different search" msgstr "Essayez une recherche différente" #: data/ui/ErrorPerspective.ui:16 msgid "Here, rodent, rodent, rodent…" msgstr "Où es-tu petit rongeur ?" #: data/ui/ErrorPerspective.ui:69 msgid "Uh Oh! Something went wrong…" msgstr "Oups, quelque chose s'est mal passé..." #: data/ui/LedDialog.ui:51 data/ui/LedDialog.ui:192 msgid "Choose a color for the LED" msgstr "Choisissez une couleur pour la LED" #: data/ui/LedDialog.ui:78 data/ui/LedDialog.ui:235 msgid "Choose a brightness for the LED" msgstr "Choisissez une valeur de luminosité pour la LED" #: data/ui/LedDialog.ui:92 data/ui/LedDialog.ui:248 msgid "Brightness" msgstr "Luminosité" #: data/ui/LedDialog.ui:120 data/ui/LedDialog.ui:276 msgid "Choose an effect duration for the LED" msgstr "Choisissez une durée d'effet pour la LED" #: data/ui/LedDialog.ui:158 data/ui/LedDialog.ui:314 msgid "Effect duration" msgstr "Durée de l'effet" #: data/ui/LedDialog.ui:195 msgid "Pick a Color for the LED" msgstr "Sélectionnez une couleur pour la LED" #: data/ui/LedDialog.ui:209 msgid "Color" msgstr "Couleur" #: data/ui/LedDialog.ui:355 msgid "This LED is off" msgstr "Cette LED est éteinte" #: data/ui/MousePerspective.ui:43 msgid "Something went wrong. The device has been reset to a previous state." msgstr "" "Quelque chose s'est mal passé. Le périphérique a été remis à un état " "antérieur." #: data/ui/MousePerspective.ui:116 msgid "Click to switch to another profile" msgstr "Cliquez pour choisir un autre profil" #: data/ui/MousePerspective.ui:131 msgid "Add profile" msgstr "Ajouter un profil" #: data/ui/MousePerspective.ui:135 msgid "Add a new profile to the device" msgstr "Ajouter un profil au périphérique" #: data/ui/MousePerspective.ui:163 msgid "Select another profile" msgstr "Choisir un autre profil" #: data/ui/MousePerspective.ui:181 msgid "Commit the changes to the device" msgstr "Appliquer les changements au périphérique" #: data/ui/OptionButton.ui:9 msgid "Open the configuration dialog" msgstr "Ouvrir le panneau de configuration" #: data/ui/ProfileRow.ui:16 msgid "Remove this profile from the device" msgstr "Supprimer ce profil du périphérique" #. Translators: this is used to indicate the active resolution. #: data/ui/ResolutionRow.ui:37 msgid "active" msgstr "actif" #: data/ui/ResolutionRow.ui:69 msgid "Set this resolution's dpi" msgstr "Définir le DPI de cette résolution" #: data/ui/ResolutionRow.ui:101 msgid "Disable this resolution" msgstr "Désactiver cette résolution" #: data/ui/ResolutionRow.ui:112 msgid "Set active" msgstr "Définir comme actif" #: data/ui/ResolutionRow.ui:117 msgid "Set this resolution as active" msgstr "Définir cette résolution comme active" #: data/ui/ResolutionsPage.ui:45 msgid "Add a new resolution to the profile" msgstr "Ajouter une nouvelle résolution au profil" #: data/ui/WelcomePerspective.ui:20 msgid "Welcome" msgstr "Bienvenue" #: data/ui/WelcomePerspective.ui:38 msgctxt "A subtitle under the \"Welcome\" title." msgid "Select a device to configure it" msgstr "Sélectionnez un périphérique pour le configurer" #: data/ui/WelcomePerspective.ui:88 msgctxt "A tooltip over the list of devices." msgid "Select a device to configure it" msgstr "Sélectionnez un périphérique pour le configurer" #: data/ui/WelcomePerspective.ui:118 msgid "Select a Device" msgstr "Sélectionnez un périphérique" #: data/ui/Window.ui:8 msgid "_About Piper" msgstr "_À propos de Piper" piper-0.8/po/hr.po000066400000000000000000000367611467456234500141240ustar00rootroot00000000000000# Croatian Piper translation # Copyright (C) 2017 gogo # This file is distributed under the same license as the piper package. # gogo , 2017. # msgid "" msgstr "" "Project-Id-Version: piper\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2020-05-20 10:47+0200\n" "PO-Revision-Date: 2020-05-20 10:53+0200\n" "Last-Translator: gogo \n" "Language-Team: Croatian <>\n" "Language: hr\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Generator: Poedit 2.0.6\n" "Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n" "%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" #: data/org.freedesktop.Piper.desktop.in:3 #: data/org.freedesktop.Piper.appdata.xml.in.in:7 msgid "Piper" msgstr "Piper" #: data/org.freedesktop.Piper.desktop.in:4 #: data/org.freedesktop.Piper.appdata.xml.in.in:8 msgid "Configurable mouse configuration utility" msgstr "Pomagalo za podešavanje miša" #. Translators: Do NOT translate or transliterate this text (this is an icon file name)! #: data/org.freedesktop.Piper.desktop.in:7 msgid "org.freedesktop.Piper" msgstr "org.freedesktop.Piper" #. Translators: Search terms to find this application. Do NOT translate or localize the semicolons! The list MUST also end with a semicolon! #: data/org.freedesktop.Piper.desktop.in:12 msgid "gaming;configuration;mouse;mice;" msgstr "igranje;prilagodba;podešavanje;miš;" #: data/org.freedesktop.Piper.appdata.xml.in.in:10 msgid "" "Piper is a graphical user interface to configure gaming mice. Configuration " "options include changing the resolution (DPI) of the mouse, adding and " "removing profiles, setting LED colors and changing button behaviors." msgstr "" "Piper je korisničko grafičko sučelje za podešavanje miševa namijenjenih " "igranju. Mogućnosti podešavanja uključuju promjenu razlučivosti (DPI) miša, " "dodavanje i uklanjanje profila, prilagodba LED boja i ponašanja tipka." #: data/org.freedesktop.Piper.appdata.xml.in.in:16 msgid "" "Piper requires libratbag’s ratbagd, the daemon to actually communicate with " "the mice. Piper is merely a front end to ratbagd, ratbagd must be installed " "and running when Piper is launched." msgstr "" "Piper zahtijeva libratbagov ratbag, pozadinski program za komunikaciju s " "mišem. Piper je prednji program za ratbagd, ratbagd mora biti instaliran i " "pokrenut kada se Piper pokrene." #: data/org.freedesktop.Piper.appdata.xml.in.in:27 msgid "The button configuraton page" msgstr "Stranica podešavanja tipki" #: data/org.freedesktop.Piper.appdata.xml.in.in:31 msgid "The LED configuraton page" msgstr "Stranica LED podešavanja" #: data/org.freedesktop.Piper.appdata.xml.in.in:35 msgid "The resolution configuraton page" msgstr "Stranica podešavanja razlučivosti" #. Translators: section header for mapping one button's click to another. #: piper/buttondialog.py:141 msgid "Button mapping" msgstr "Mapiranje tipki" #. Translators: section header for assigning special functions to buttons. #: piper/buttondialog.py:150 msgid "Special mapping" msgstr "Posebno mapiranje" #. Translators: the {} will be replaced with the button index, e.g. #. "Button 1 click". #: piper/buttondialog.py:222 piper/buttonspage.py:90 msgid "Button {} click" msgstr "Tipka {} klik" #: piper/buttonspage.py:94 msgid "Macro: {}" msgstr "Makro: {}" #. Translators: the button is turned disabled, e.g. off. #: piper/buttonspage.py:97 msgid "Disabled" msgstr "Onemogućeno" #. Translators: the button has an unknown function. #: piper/buttonspage.py:100 piper/ratbagd.py:665 msgid "Unknown" msgstr "Nepoznato" #: piper/buttonspage.py:108 msgid "Configure button {}" msgstr "Prilagodi tipku {}" #: piper/mouseperspective.py:90 data/ui/ResolutionsPage.ui:209 msgid "Resolutions" msgstr "Razlučivost" #: piper/mouseperspective.py:92 msgid "Buttons" msgstr "Tipke" #: piper/mouseperspective.py:94 msgid "LEDs" msgstr "LED" #: piper/ratbagd.py:655 msgid "Left mouse button click" msgstr "Lijeva tipka klika miša" #: piper/ratbagd.py:656 msgid "Right mouse button click" msgstr "Desna tipka klika miša" #: piper/ratbagd.py:657 msgid "Middle mouse button click" msgstr "Srednja tipka klika miša" #: piper/ratbagd.py:658 msgid "Backward" msgstr "Natrag" #: piper/ratbagd.py:659 msgid "Forward" msgstr "Naprijed" #: piper/ratbagd.py:664 msgid "Invalid" msgstr "Neispravno" #: piper/ratbagd.py:666 msgid "Doubleclick" msgstr "Dvostruki klik" #: piper/ratbagd.py:667 msgid "Wheel Left" msgstr "Kotačić lijevo" #: piper/ratbagd.py:668 msgid "Wheel Right" msgstr "Kotačić desno" #: piper/ratbagd.py:669 msgid "Wheel Up" msgstr "Kotačić gore" #: piper/ratbagd.py:670 msgid "Wheel Down" msgstr "Kotačić dolje" #: piper/ratbagd.py:671 msgid "Ratchet Mode" msgstr "Zaustavljački način" #: piper/ratbagd.py:672 msgid "Cycle Resolution Up" msgstr "Povećaj kružnu razlučivost" #: piper/ratbagd.py:673 msgid "Cycle Resolution Down" msgstr "Smanji kružnu razlučivost" #: piper/ratbagd.py:674 msgid "Resolution Up" msgstr "Povećaj razlučivost" #: piper/ratbagd.py:675 msgid "Resolution Down" msgstr "Smanji razlučivost" #: piper/ratbagd.py:676 msgid "Resolution Switch" msgstr "Prebaci razlučivosti" #: piper/ratbagd.py:677 msgid "Default Resolution" msgstr "Zadana razlučivost" #: piper/ratbagd.py:678 msgid "Cycle Profile Up" msgstr "Veći kružni profil" #: piper/ratbagd.py:679 msgid "Cycle Profile Down" msgstr "Manji kružni profil" #: piper/ratbagd.py:680 msgid "Profile Up" msgstr "Veći profil" #: piper/ratbagd.py:681 msgid "Profile Down" msgstr "Manji profil" #: piper/ratbagd.py:682 msgid "Second Mode" msgstr "Pomoćni način" #: piper/ratbagd.py:683 msgid "Battery Level" msgstr "Razina baterije" #. Translators: this is used when there is no macro to preview. #: piper/ratbagd.py:813 data/ui/ButtonDialog.ui:106 data/ui/ButtonDialog.ui:187 msgid "None" msgstr "Nedodjeljeno" #. Translators: the LED is off. #: piper/ratbagd.py:895 data/ui/LedDialog.ui:395 msgid "Off" msgstr "Isključeno" #. Translators: the LED has a single, solid color. #: piper/ratbagd.py:897 data/ui/LedDialog.ui:66 msgid "Solid" msgstr "Nepromjenjivo" #. Translators: the LED is cycling between red, green and blue. #: piper/ratbagd.py:899 data/ui/LedDialog.ui:189 msgid "Cycle" msgstr "Kružno" #. Translators: the LED's is pulsating a single color on different #. brightnesses. #: piper/ratbagd.py:902 data/ui/LedDialog.ui:355 msgid "Breathing" msgstr "Pulsirajuće" #: piper/window.py:54 msgid "Cannot connect to ratbagd" msgstr "Nemoguće povezivanje s ratbagdom" #: piper/window.py:55 msgid "" "Please make sure ratbagd is running and your user is in the required group" msgstr "" "Pobrinite se da je ratbagd pokrenuti i da je vaše korisničko ime dodano " "zahtijevanoj grupi" #: piper/window.py:58 msgid "Incompatible ratbagd API version (required: {}, provided: {})" msgstr "Nekompatibilna ratbagd API inačica (zahtijevana: {}, omogućena: {})" #: piper/window.py:59 msgid "Please update both piper and libratbag to the latest versions" msgstr "Nadopunite piper i libratbag na najnoviju dostupnu inačicu" #: piper/window.py:73 piper/window.py:127 msgid "Cannot find any devices" msgstr "Nemoguć pronalazak prikladnih uređaja" #: piper/window.py:74 piper/window.py:128 msgid "Please make sure your device is supported and plugged in" msgstr "Pobrinite se da je vaš uređaj podržan i priključen" #: piper/window.py:86 msgid "There are unapplied changes. Are you sure you want to quit?" msgstr "Postoje neprimijenjene promjene. Sigurno želite zatvoriti?" #: piper/window.py:95 msgid "Ooops. ratbagd has disappeared" msgstr "Ups, ratbagd je nestao" #: piper/window.py:96 msgid "Please restart Piper" msgstr "Ponovno pokrenite Piper" #. The current device disconnected, which can only happen from the #. mouse perspective as we'd otherwise be in the welcome screen with #. more than one device remaining. Hence, we display the error #. perspective. #: piper/window.py:119 msgid "Your device disconnected!" msgstr "Vaš uređaj nije priključen!" #: piper/window.py:120 msgid "Please make sure your device is plugged in" msgstr "Pobrinite se da je vaš uređaj priključen" #: piper/window.py:159 msgid "Cannot display device SVG" msgstr "Nemoguć prikaz SVG uređaja" #: piper/window.py:166 msgid "Newer version of ratbagd required" msgstr "Potrebna je nova inačica ratbagda" #: piper/window.py:167 msgid "Please update to the latest available version" msgstr "Nadopunite na najnoviju dostupnu inačicu" #: piper/window.py:169 msgid "Unknown exception occurred" msgstr "Dogodila se nepoznata iznimka" #: data/ui/AboutDialog.ui.in:10 msgid "Version: @version@" msgstr "Inačica: @version@" #: data/ui/AboutDialog.ui.in:12 msgid "Visit Piper on GitHub" msgstr "Posjetite Piper na GitHubu" #: data/ui/AboutDialog.ui.in:13 msgid "translator-credits" msgstr "" "Launchpad Contributions:\n" " gogo https://launchpad.net/~trebelnik-stefina" #: data/ui/ButtonDialog.ui:65 msgid "Search for a button mapping" msgstr "Pretraži mapiranje tipki" #: data/ui/ButtonDialog.ui:91 msgid "Capture a macro for this button" msgstr "Uhvati makro za ovu tipku" #: data/ui/ButtonDialog.ui:104 msgid "The currently set macro" msgstr "Trenutno postavljeni makro" #: data/ui/ButtonDialog.ui:129 msgid "Send keystroke" msgstr "Pošalji pritisak tipke" #: data/ui/ButtonDialog.ui:169 msgid "Enter a new key sequence for the macro." msgstr "Unesi novi slijed tipke za makro." #: data/ui/ButtonDialog.ui:221 msgid "Press Escape to cancel or Return to accept." msgstr "Pritisni Escape za prekidanje ili Return za prihvaćanje." #: data/ui/ButtonDialog.ui:252 msgid "Set the device’s handedness." msgstr "Postavite za ljevu/desnu ruku uređaja." #: data/ui/ButtonDialog.ui:270 msgid "" "This allows you to swap the order of the primary mouse buttons. In left-" "handed mode, the physical left mouse button generates a right mouse click " "and vice versa." msgstr "" "Ovo vam omogućuje zamjenu poredka glavnih tipka miša. U lijevorukom načinu " "rada, fizička lijeva tipka miša generira desni klik miša i obrnuto." #: data/ui/ButtonDialog.ui:290 msgid "Left Handed" msgstr "Lijevoruko" #: data/ui/ButtonDialog.ui:295 msgid "The left mouse button generates a left mouse click" msgstr "Lijeva tipka miša generira lijevi klik miša" #: data/ui/ButtonDialog.ui:309 msgid "Right Handed" msgstr "Desnoruko" #: data/ui/ButtonDialog.ui:314 msgid "The left mouse button generates a right mouse click" msgstr "Lijeva tipka miša generira desni klik miša" #: data/ui/ButtonDialog.ui:354 data/ui/LedDialog.ui:414 msgid "Cancel" msgstr "Odustani" #: data/ui/ButtonDialog.ui:356 data/ui/LedDialog.ui:418 msgid "Ignore any changes made" msgstr "Zanemari sve napravljene promjene" #: data/ui/ButtonDialog.ui:362 data/ui/LedDialog.ui:430 #: data/ui/MousePerspective.ui:132 msgid "Apply" msgstr "Primjeni" #: data/ui/ButtonDialog.ui:365 data/ui/LedDialog.ui:435 msgid "Apply any changes made" msgstr "Primijeni sve napravljene promjene" #: data/ui/ButtonDialog.ui:405 msgid "No button mapping found" msgstr "Nema pronađenih mapiranja tipki" #: data/ui/ButtonDialog.ui:421 msgid "Try a different search" msgstr "Pokušajte drugačiju pretragu" #: data/ui/ErrorPerspective.ui:16 msgid "Here, rodent, rodent, rodent…" msgstr "Ovdje, glodavac, glodavac, glodavac…" #: data/ui/ErrorPerspective.ui:69 msgid "Uh Oh! Something went wrong…" msgstr "Ups! Nešto je pošlo po krivu…" #: data/ui/ErrorPerspective.ui:73 data/ui/WelcomePerspective.ui:123 msgid "Quit" msgstr "Zatvori" #: data/ui/LedDialog.ui:58 data/ui/LedDialog.ui:209 msgid "Choose a color for the LED" msgstr "Odaberi boju za LED" #: data/ui/LedDialog.ui:90 data/ui/LedDialog.ui:257 msgid "Choose a brightness for the LED" msgstr "Odaberi svjetlinu za LED" #: data/ui/LedDialog.ui:104 data/ui/LedDialog.ui:270 msgid "Brightness" msgstr "Svjetlina" #: data/ui/LedDialog.ui:135 data/ui/LedDialog.ui:301 msgid "Choose an effect duration for the LED" msgstr "Odaberi trajanje efekta za LED" #: data/ui/LedDialog.ui:153 data/ui/LedDialog.ui:319 msgid "ms" msgstr "ms" #: data/ui/LedDialog.ui:175 data/ui/LedDialog.ui:341 msgid "Effect duration" msgstr "Trajanje efekta" #: data/ui/LedDialog.ui:212 msgid "Pick a Color for the LED" msgstr "Odaberi boju za LED" #: data/ui/LedDialog.ui:226 msgid "Color" msgstr "Boja" #: data/ui/LedDialog.ui:380 msgid "This LED is off" msgstr "Ovaj LED je isključen" #: data/ui/MousePerspective.ui:44 msgid "Something went wrong. The device has been reset to a previous state." msgstr "Nešto je pošlo po krivu. Uređaj je postavljen na prijašnje stanje." #: data/ui/MousePerspective.ui:101 msgid "Select another profile" msgstr "Odaberi drugi profil" #: data/ui/MousePerspective.ui:126 msgid "Commit the changes to the device" msgstr "Primijeni promjene na uređaju" #: data/ui/MousePerspective.ui:170 msgid "Click to switch to another profile" msgstr "Klikni za prebacivanje na drugi profil" #: data/ui/MousePerspective.ui:185 msgid "Add profile" msgstr "Dodaj profil" #: data/ui/MousePerspective.ui:189 msgid "Add a new profile to the device" msgstr "Dodaj novi profil na uređaj" #: data/ui/OptionButton.ui:9 msgid "Open the configuration dialog" msgstr "Otvori dijalog prilagodbe" #: data/ui/ProfileRow.ui:16 msgid "Remove this profile from the device" msgstr "Ukloni ovaj profil sa uređaja" #. Translators: this is used to indicate the active resolution. #: data/ui/ResolutionRow.ui:37 msgid "Active" msgstr "Aktivno" #: data/ui/ResolutionRow.ui:77 msgid "Set this resolution’s DPI" msgstr "Postavi ovu DPI razlučivosti" #. Translators: the rate at which the device reports movement. #: data/ui/ResolutionsPage.ui:43 msgid "Report rate" msgstr "Frekvencija" #: data/ui/ResolutionsPage.ui:60 msgid "Change the profile’s report rate" msgstr "Promijeni frekvenciju profila" #: data/ui/ResolutionsPage.ui:105 msgid "Hz" msgstr "Hz" #. Translators: the sensitivity of the device's sensor. #: data/ui/ResolutionsPage.ui:125 msgid "Sensitivity" msgstr "Osjetljivost" #: data/ui/ResolutionsPage.ui:174 msgid "Add a new resolution to the profile" msgstr "Dodaj novu razlučivost u profil" #: data/ui/WelcomePerspective.ui:20 msgid "Welcome" msgstr "Dobrodošli" #: data/ui/WelcomePerspective.ui:38 msgctxt "A subtitle under the \"Welcome\" title." msgid "Select a device to configure it" msgstr "Odaberite uređaj za prilagodbu" #: data/ui/WelcomePerspective.ui:89 msgctxt "A tooltip over the list of devices." msgid "Select a device to configure it" msgstr "Odaberite uređaj za prilagodbu" #: data/ui/WelcomePerspective.ui:119 msgid "Select a Device" msgstr "Odaberi uređaj" #: data/ui/Window.ui:8 msgid "_About Piper" msgstr "_O Piperu" #~ msgid "Visit Piper’s website" #~ msgstr "Posjetite Piper web stranicu" #~ msgid "Remove this resolution from the profile" #~ msgstr "Ukloni ovu razlučivost sa uređaja" #~ msgid "Profile {}" #~ msgstr "Profil {}" #~ msgid "Set the device's handedness." #~ msgstr "Postavite za ljevu/desnu ruku uređaja." #~ msgid "Here, rodent, rodent, rodent..." #~ msgstr "Ovdje, glodavac, glodavac, glodavac..." #~ msgid "Uh Oh! Something went wrong..." #~ msgstr "Ups! Nešto je pošlo po krivu..." #~ msgid "Choose an effect rate for the LED" #~ msgstr "Odaberi frekvenciju efekta za LED" #~ msgid "Effect rate" #~ msgstr "Frekvencija efekta" #~ msgid "_About" #~ msgstr "_O programu" #~ msgid "_Quit" #~ msgstr "_Zatvori" #~ msgid "Failed to commit changes to the device" #~ msgstr "Neuspješno primijenjivanje promjena na uređaju" #~ msgid "Set this resolution's DPI" #~ msgstr "Postavi ovu DPI razlučivost" #~ msgid "Change the profile's report rate" #~ msgstr "Promijeni frekvenciju profila" piper-0.8/po/it.po000066400000000000000000000353571467456234500141270ustar00rootroot00000000000000# Italian translations for piper # Copyright (C) 2017-2020 the piper authors # This file is distributed under the same license as the piper package. # Francesco Venturoli , 2020. # #, fuzzy msgid "" msgstr "" "Project-Id-Version: piper\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2020-01-28 22:04+0100\n" "PO-Revision-Date: 2020-01-28 22:10+0100\n" "Last-Translator: Francesco Venturoli \n" "Language-Team: Italian <>\n" "Language: it\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" #: data/org.freedesktop.Piper.desktop.in:3 #: data/org.freedesktop.Piper.appdata.xml.in.in:7 msgid "Piper" msgstr "Piper" #: data/org.freedesktop.Piper.desktop.in:4 #: data/org.freedesktop.Piper.appdata.xml.in.in:8 msgid "Configurable mouse configuration utility" msgstr "Utility di configurazione per mouse configurabili" #. Translators: Do NOT translate or transliterate this text (this is an icon file name)! #: data/org.freedesktop.Piper.desktop.in:7 msgid "org.freedesktop.Piper" msgstr "org.freedesktop.Piper" #. Translators: Search terms to find this application. Do NOT translate or localize the semicolons! The list MUST also end with a semicolon! #: data/org.freedesktop.Piper.desktop.in:12 msgid "gaming;configuration;mouse;mice;" msgstr "gaming;gioco;configurazione;mouse;" #: data/org.freedesktop.Piper.appdata.xml.in.in:10 msgid "" "Piper is a graphical user interface to configure gaming mice. Configuration " "options include changing the resolution (DPI) of the mouse, adding and " "removing profiles, setting LED colors and changing button behaviors." msgstr "" "Piper è un'interfaccia grafica per configurare mouse da gioco. Le opzioni " "di configurazione includono il cambiamento della risoluzione (DPI) del mouse, " "l'aggiunta e la rimozione di profili, l'impostazione dei colori dei LED e il " "cambiamento del comportamento dei pulsanti." #: data/org.freedesktop.Piper.appdata.xml.in.in:16 msgid "" "Piper requires libratbag’s ratbagd, the daemon to actually communicate with " "the mice. Piper is merely a front end to ratbagd, ratbagd must be installed " "and running when Piper is launched." msgstr "" "Piper necessita di ratbagd (incluso in libratbag), il demone che comunica " "effettivamente con il mouse. Piper è una semplice interfaccia per ratbagd, " "ratbagd deve essere installato e in esecuzione quando Piper viene lanciato." #: data/org.freedesktop.Piper.appdata.xml.in.in:33 msgid "The button configuraton page" msgstr "La pagina di configurazione dei pulsanti" #: data/org.freedesktop.Piper.appdata.xml.in.in:37 msgid "The LED configuraton page" msgstr "La pagina di configurazione dei LED" #: data/org.freedesktop.Piper.appdata.xml.in.in:41 msgid "The resolution configuraton page" msgstr "La pagina di configurazione della risoluzione" #. Translators: section header for mapping one button's click to another. #: piper/buttondialog.py:141 msgid "Button mapping" msgstr "Mappatura dei pulsanti" #. Translators: section header for assigning special functions to buttons. #: piper/buttondialog.py:150 msgid "Special mapping" msgstr "Mappatura speciale" #. Translators: the {} will be replaced with the button index, e.g. #. "Button 1 click". #: piper/buttondialog.py:222 piper/buttonspage.py:90 msgid "Button {} click" msgstr "Click pulsante {}" #: piper/buttonspage.py:94 msgid "Macro: {}" msgstr "Macro: {}" #. Translators: the button is turned disabled, e.g. off. #: piper/buttonspage.py:97 msgid "Disabled" msgstr "Disabilitato" #. Translators: the button has an unknown function. #: piper/buttonspage.py:100 piper/ratbagd.py:665 msgid "Unknown" msgstr "Sconosciuto" #: piper/buttonspage.py:108 msgid "Configure button {}" msgstr "Configura pulsante {}" #: piper/mouseperspective.py:90 data/ui/ResolutionsPage.ui:209 msgid "Resolutions" msgstr "Risoluzioni" #: piper/mouseperspective.py:92 msgid "Buttons" msgstr "Pulsanti" #: piper/mouseperspective.py:94 msgid "LEDs" msgstr "LED" #: piper/ratbagd.py:655 msgid "Left mouse button click" msgstr "Click pulsante sinistro" #: piper/ratbagd.py:656 msgid "Right mouse button click" msgstr "Click pulsante destro" #: piper/ratbagd.py:657 msgid "Middle mouse button click" msgstr "Click pulsante centrale" #: piper/ratbagd.py:658 msgid "Backward" msgstr "Indietro" #: piper/ratbagd.py:659 msgid "Forward" msgstr "Avanti" #: piper/ratbagd.py:664 msgid "Invalid" msgstr "Invalido" #: piper/ratbagd.py:666 msgid "Doubleclick" msgstr "Doppio click" #: piper/ratbagd.py:667 msgid "Wheel Left" msgstr "Rotella a sinistra" #: piper/ratbagd.py:668 msgid "Wheel Right" msgstr "Rotella a destra" #: piper/ratbagd.py:669 msgid "Wheel Up" msgstr "Rotella su" #: piper/ratbagd.py:670 msgid "Wheel Down" msgstr "Rotella giù" #: piper/ratbagd.py:671 msgid "Ratchet Mode" msgstr "Rotazione graduale" #: piper/ratbagd.py:672 msgid "Cycle Resolution Up" msgstr "Cicla risoluzione su" #: piper/ratbagd.py:673 msgid "Cycle Resolution Down" msgstr "Cicla risoluzione giù" #: piper/ratbagd.py:674 msgid "Resolution Up" msgstr "Risoluzione su" #: piper/ratbagd.py:675 msgid "Resolution Down" msgstr "Risoluzione giù" #: piper/ratbagd.py:676 msgid "Resolution Switch" msgstr "Cambio risoluzione" #: piper/ratbagd.py:677 msgid "Default Resolution" msgstr "Risoluzione predefinita" #: piper/ratbagd.py:678 msgid "Cycle Profile Up" msgstr "Cicla profilo su" #: piper/ratbagd.py:679 msgid "Cycle Profile Down" msgstr "Cicla profilo giù" #: piper/ratbagd.py:680 msgid "Profile Up" msgstr "Profilo su" #: piper/ratbagd.py:681 msgid "Profile Down" msgstr "Profilo giù" #: piper/ratbagd.py:682 msgid "Second Mode" msgstr "Seconda modalità" #: piper/ratbagd.py:683 msgid "Battery Level" msgstr "Livello batteria" #. Translators: this is used when there is no macro to preview. #: piper/ratbagd.py:813 data/ui/ButtonDialog.ui:106 data/ui/ButtonDialog.ui:187 msgid "None" msgstr "Nessuno" #. Translators: the LED is off. #: piper/ratbagd.py:895 data/ui/LedDialog.ui:395 msgid "Off" msgstr "Spento" #. Translators: the LED has a single, solid color. #: piper/ratbagd.py:897 data/ui/LedDialog.ui:66 msgid "Solid" msgstr "Fisso" #. Translators: the LED is cycling between red, green and blue. #: piper/ratbagd.py:899 data/ui/LedDialog.ui:189 msgid "Cycle" msgstr "Ciclo" #. Translators: the LED's is pulsating a single color on different #. brightnesses. #: piper/ratbagd.py:902 data/ui/LedDialog.ui:355 msgid "Breathing" msgstr "Respiro" #: piper/window.py:54 msgid "Cannot connect to ratbagd" msgstr "Impossibile connetersi a ratbagd" #: piper/window.py:55 msgid "" "Please make sure ratbagd is running and your user is in the required group" msgstr "" "Assicurati che ratbagd sia in esecuzione e che il tuo utente sia nel gruppo corretto" #: piper/window.py:58 msgid "Incompatible ratbagd API version (required: {}, provided: {})" msgstr "Versione delle API di ratbagd incompatibile (richiesta: {}, fornita: {})" #: piper/window.py:59 msgid "Please update both piper and libratbag to the latest versions" msgstr "Aggiorna piper e ratbagd alle ultime versioni" #: piper/window.py:73 piper/window.py:127 msgid "Cannot find any devices" msgstr "Impossibile trovare dispositivi" #: piper/window.py:74 piper/window.py:128 msgid "Please make sure your device is supported and plugged in" msgstr "Assicurati che il tuo dispositivo sia supportato e collegato" #: piper/window.py:86 msgid "There are unapplied changes. Are you sure you want to quit?" msgstr "Ci sono cambiamenti non applicati. Sei sicuro di voler uscire?" #: piper/window.py:95 msgid "Ooops. ratbagd has disappeared" msgstr "Ooops. ratbagd è scomparso" #: piper/window.py:96 msgid "Please restart Piper" msgstr "Riavvia Piper" #. The current device disconnected, which can only happen from the #. mouse perspective as we'd otherwise be in the welcome screen with #. more than one device remaining. Hence, we display the error #. perspective. #: piper/window.py:119 msgid "Your device disconnected!" msgstr "Il tuo dispositivo si è disconnesso!" #: piper/window.py:120 msgid "Please make sure your device is plugged in" msgstr "Assicurati che il tuo dispositivo sia collegato" #: piper/window.py:159 msgid "Cannot display device SVG" msgstr "Impossibile mostrare SVG dispositivo" #: piper/window.py:166 msgid "Newer version of ratbagd required" msgstr "Versione più recente di ratbagd richiesta" #: piper/window.py:167 msgid "Please update to the latest available version" msgstr "Aggiorna all'ultima versione disponibile" #: piper/window.py:169 msgid "Unknown exception occurred" msgstr "Eccezione sconosciuta" #: data/ui/AboutDialog.ui.in:10 msgid "Version: @version@" msgstr "Versione: @version@" #: data/ui/AboutDialog.ui.in:12 msgid "Visit Piper on GitHub" msgstr "Visita Piper su GitHub" #: data/ui/AboutDialog.ui.in:13 msgid "translator-credits" msgstr "Francesco Venturoli , 2020" #: data/ui/ButtonDialog.ui:65 msgid "Search for a button mapping" msgstr "Cerca mappatura di un pulsante" #: data/ui/ButtonDialog.ui:91 msgid "Capture a macro for this button" msgstr "Registra una macro per questo pulsante" #: data/ui/ButtonDialog.ui:104 msgid "The currently set macro" msgstr "La macro correntemente impostata" #: data/ui/ButtonDialog.ui:129 msgid "Send keystroke" msgstr "Invia pressione di un tasto" #: data/ui/ButtonDialog.ui:169 msgid "Enter a new key sequence for the macro." msgstr "Inserisci una nuova sequenza per la macro." #: data/ui/ButtonDialog.ui:221 msgid "Press Escape to cancel or Return to accept." msgstr "Premi Esc per annullare o Invio per accettare." #: data/ui/ButtonDialog.ui:252 msgid "Set the device’s handedness." msgstr "Imposta la mano dominante per il dispositivo" #: data/ui/ButtonDialog.ui:270 msgid "" "This allows you to swap the order of the primary mouse buttons. In left-" "handed mode, the physical left mouse button generates a right mouse click " "and vice versa." msgstr "" "Questo permette di scambiare l'ordine dei pulsanti principali del mouse. In " "modalità mancina, il pulsante fisico sinisto del mouse genera un click destro " "e viceversa." #: data/ui/ButtonDialog.ui:290 msgid "Left Handed" msgstr "Mancino" #: data/ui/ButtonDialog.ui:295 msgid "The left mouse button generates a left mouse click" msgstr "Il pulsante sinistro del mouse genera un click sinistro" #: data/ui/ButtonDialog.ui:309 msgid "Right Handed" msgstr "Destrorso" #: data/ui/ButtonDialog.ui:314 msgid "The left mouse button generates a right mouse click" msgstr "Il pulsante sinistro del mouse genera un click destro" #: data/ui/ButtonDialog.ui:354 data/ui/LedDialog.ui:414 msgid "Cancel" msgstr "Annulla" #: data/ui/ButtonDialog.ui:356 data/ui/LedDialog.ui:418 msgid "Ignore any changes made" msgstr "Ignora i cambiamenti effettuati" #: data/ui/ButtonDialog.ui:362 data/ui/LedDialog.ui:430 #: data/ui/MousePerspective.ui:132 msgid "Apply" msgstr "Applica" #: data/ui/ButtonDialog.ui:365 data/ui/LedDialog.ui:435 msgid "Apply any changes made" msgstr "Applica i cambiamenti effettuati" #: data/ui/ButtonDialog.ui:405 msgid "No button mapping found" msgstr "Nessuna mappatura pulsante trovata" #: data/ui/ButtonDialog.ui:421 msgid "Try a different search" msgstr "Prova ad effettuare un'altra ricerca" #: data/ui/ErrorPerspective.ui:16 msgid "Here, rodent, rodent, rodent…" msgstr "Qui, roditore, roditore, roditore…" #: data/ui/ErrorPerspective.ui:69 msgid "Uh Oh! Something went wrong…" msgstr "Oh oh! Qualcosa è andato storto…" #: data/ui/ErrorPerspective.ui:73 data/ui/WelcomePerspective.ui:123 msgid "Quit" msgstr "Esci" #: data/ui/LedDialog.ui:58 data/ui/LedDialog.ui:209 msgid "Choose a color for the LED" msgstr "Scegli un colore per il LED" #: data/ui/LedDialog.ui:90 data/ui/LedDialog.ui:257 msgid "Choose a brightness for the LED" msgstr "Scegli una luminosità per il LED" #: data/ui/LedDialog.ui:104 data/ui/LedDialog.ui:270 msgid "Brightness" msgstr "Luminosità" #: data/ui/LedDialog.ui:135 data/ui/LedDialog.ui:301 msgid "Choose an effect duration for the LED" msgstr "Scegli la durata dell'effetto del LED" #: data/ui/LedDialog.ui:153 data/ui/LedDialog.ui:319 msgid "ms" msgstr "ms" #: data/ui/LedDialog.ui:175 data/ui/LedDialog.ui:341 msgid "Effect duration" msgstr "Durata effetto" #: data/ui/LedDialog.ui:212 msgid "Pick a Color for the LED" msgstr "Scegli un colore per il LED" #: data/ui/LedDialog.ui:226 msgid "Color" msgstr "Colore" #: data/ui/LedDialog.ui:380 msgid "This LED is off" msgstr "Questo LED è spento" #: data/ui/MousePerspective.ui:44 msgid "Something went wrong. The device has been reset to a previous state." msgstr "Qualcosa è andato storto. Lo stato precedente del dispositivo è stato ripristinato." #: data/ui/MousePerspective.ui:101 msgid "Select another profile" msgstr "Scegli un altro profilo" #: data/ui/MousePerspective.ui:126 msgid "Commit the changes to the device" msgstr "Applica i cambiamenti al dispositivo" #: data/ui/MousePerspective.ui:170 msgid "Click to switch to another profile" msgstr "Clicca per passare ad un altro profilo" #: data/ui/MousePerspective.ui:185 msgid "Add profile" msgstr "Aggiungi profilo" #: data/ui/MousePerspective.ui:189 msgid "Add a new profile to the device" msgstr "Aggiungi un nuovo profilo al dispositivo" #: data/ui/OptionButton.ui:9 msgid "Open the configuration dialog" msgstr "Apri il dialogo di configurazione" #: data/ui/ProfileRow.ui:16 msgid "Remove this profile from the device" msgstr "Rimuovi questo profilo dal dispositivo" #. Translators: this is used to indicate the active resolution. #: data/ui/ResolutionRow.ui:37 msgid "Active" msgstr "Attiva" #: data/ui/ResolutionRow.ui:77 msgid "Set this resolution’s DPI" msgstr "Imposta i DPI di questa risoluzione" #. Translators: the rate at which the device reports movement. #: data/ui/ResolutionsPage.ui:43 msgid "Report rate" msgstr "Frequenza di aggiornamento" #: data/ui/ResolutionsPage.ui:60 msgid "Change the profile’s report rate" msgstr "Cambia la frequenza di aggiornamento del profilo" #: data/ui/ResolutionsPage.ui:105 msgid "Hz" msgstr "Hz" #. Translators: the sensitivity of the device's sensor. #: data/ui/ResolutionsPage.ui:125 msgid "Sensitivity" msgstr "Sensibilità" #: data/ui/ResolutionsPage.ui:174 msgid "Add a new resolution to the profile" msgstr "Aggiungi una nuova risoluzione al profilo" #: data/ui/WelcomePerspective.ui:20 msgid "Welcome" msgstr "Benvenuto" #: data/ui/WelcomePerspective.ui:38 msgctxt "A subtitle under the \"Welcome\" title." msgid "Select a device to configure it" msgstr "Scegli un dispositivo per configurarlo" #: data/ui/WelcomePerspective.ui:89 msgctxt "A tooltip over the list of devices." msgid "Select a device to configure it" msgstr "Scegli un dispositivo per configurarlo" #: data/ui/WelcomePerspective.ui:119 msgid "Select a Device" msgstr "Scegli un dispositivo" #: data/ui/Window.ui:8 msgid "_About Piper" msgstr "_A proposito di Piper" piper-0.8/po/ka.po000066400000000000000000000474611467456234500141050ustar00rootroot00000000000000# Georgian translation for piper. # Copyright (C) 2023 piper's authors # This file is distributed under the same license as the piper package. # Temuri Doghonadze , 2023. # msgid "" msgstr "" "Project-Id-Version: piper\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2023-02-21 16:32+0100\n" "PO-Revision-Date: 2023-02-22 21:57+0100\n" "Last-Translator: Temuri Doghonadze \n" "Language-Team: Georgian <(nothing)>\n" "Language: ka\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: Poedit 3.2.2\n" #: data/org.freedesktop.Piper.desktop.in:3 msgid "Piper" msgstr "Piper" #: data/org.freedesktop.Piper.desktop.in:4 msgid "Configurable mouse configuration utility" msgstr "მორგებადი თაგუნას მორგების პროგრამა" #. Translators: Search terms to find this application. Do NOT translate or localize the semicolons! The list MUST also end with a semicolon! #: data/org.freedesktop.Piper.desktop.in:12 msgid "gaming;configuration;mouse;mice;" msgstr "თამაში;მორგება;თაგუნა;" #: data/org.freedesktop.Piper.appdata.xml.in.in:8 msgid "Gaming mouse configuration utility" msgstr "სათამაშო თაგუნას მორგების პროგრამა" #: data/org.freedesktop.Piper.appdata.xml.in.in:10 msgid "" "Piper is a graphical user interface to configure gaming mice. Configuration " "options include changing the resolution (DPI) of the mouse, adding and " "removing profiles, setting LED colors and changing button behaviors." msgstr "" "Piper-ი სათამაშო თაგუნების მორგების გრაფიკული ინტერფეისია. კონფიგურაციის " "პარამეტრები თაგუნას გაფართოების (DPI) შეცვლას, პროფილების წაშლას და " "დამატებას, LED-ის ფერების დაყენებას და ღილაკების ქცევის ცვლილებას შეიცავს." #: data/org.freedesktop.Piper.appdata.xml.in.in:16 msgid "" "Piper requires libratbag’s ratbagd, the daemon to actually communicate with " "the mice. Piper is merely a front end to ratbagd, ratbagd must be installed " "and running when Piper is launched." msgstr "" "Piper-ს libratbag-ის პროგრამა, ratbagd, დემონი, რომელიც თაგუნას ელაპარაკება, " "ესაჭიროება. Piper უბრალოდ წინაბოლოა, ამიტომ Piper-ის გაშვებისას ratbagd " "დაყენებული და გაშვებული უნდა იყოს." #: data/org.freedesktop.Piper.appdata.xml.in.in:27 msgid "The button configuraton page" msgstr "ღილაკის მორგების გვერდი" #: data/org.freedesktop.Piper.appdata.xml.in.in:31 msgid "The LED configuraton page" msgstr "LED-ის მორგების გვერდი" #: data/org.freedesktop.Piper.appdata.xml.in.in:35 msgid "The resolution configuraton page" msgstr "გაფართოების მორგების გვერდი" #. Translators: section header for mapping one button's click to another. #: piper/buttondialog.py:131 msgid "Button mapping" msgstr "ღილაკების მიბმა" #. Translators: section header for assigning special functions to buttons. #: piper/buttondialog.py:140 msgid "Special mapping" msgstr "სპეციალური მიბმა" #. Translators: the {} will be replaced with the button index, e.g. #. "Button 1 click". #: piper/buttondialog.py:217 piper/buttonspage.py:79 msgid "Button {} click" msgstr "ღილაკის {} წკაპი" #: piper/buttonspage.py:83 msgid "Macro: {}" msgstr "მაკრო: {}" #: piper/buttonspage.py:85 msgid "Key: {}" msgstr "ღილაკი: {}" #. Translators: the button is turned disabled, e.g. off. #: piper/buttonspage.py:88 msgid "Disabled" msgstr "გამოირთო" #. Translators: the button has an unknown function. #: piper/buttonspage.py:91 piper/ratbagd.py:727 msgid "Unknown" msgstr "უცნობი" #: piper/buttonspage.py:103 msgid "Configure button {}" msgstr "ღილაკის მორგება {}" #: piper/mouseperspective.py:76 data/ui/ResolutionsPage.ui:240 msgid "Resolutions" msgstr "გაფართოებები" #: piper/mouseperspective.py:78 msgid "Buttons" msgstr "ღილაკები" #: piper/mouseperspective.py:80 msgid "LEDs" msgstr "LED-ები" #: piper/ratbagd.py:717 msgid "Left mouse button click" msgstr "თაგუნას მარცხენა წკაპი" #: piper/ratbagd.py:718 msgid "Right mouse button click" msgstr "თაგუნას მარჯვენა წკაპი" #: piper/ratbagd.py:719 msgid "Middle mouse button click" msgstr "თაგუნას შუა წკაპი" #: piper/ratbagd.py:720 msgid "Backward" msgstr "უკან" #: piper/ratbagd.py:721 msgid "Forward" msgstr "წინ" #: piper/ratbagd.py:726 msgid "Invalid" msgstr "არასწორი" #: piper/ratbagd.py:728 msgid "Doubleclick" msgstr "ორმაგი წკაპი" #: piper/ratbagd.py:729 msgid "Wheel Left" msgstr "ბორბალი მარცხნივ" #: piper/ratbagd.py:730 msgid "Wheel Right" msgstr "ბორბალი მარჯვნივ" #: piper/ratbagd.py:731 msgid "Wheel Up" msgstr "რგოლი მაღლა" #: piper/ratbagd.py:732 msgid "Wheel Down" msgstr "რგოლი დაბლა" #: piper/ratbagd.py:733 msgid "Ratchet Mode" msgstr "ჭრიალა რეჟიმი" #: piper/ratbagd.py:734 msgid "Cycle Resolution Up" msgstr "გარჩევადობის აწევა ციკლურად" #: piper/ratbagd.py:735 msgid "Cycle Resolution Down" msgstr "გარჩევადობის დაწევა ციკლურად" #: piper/ratbagd.py:736 msgid "Resolution Up" msgstr "გარჩევადობის აწევა" #: piper/ratbagd.py:737 msgid "Resolution Down" msgstr "გარჩევადობის დაწევა" #: piper/ratbagd.py:738 msgid "Resolution Switch" msgstr "გარჩევადობის გადართვა" #: piper/ratbagd.py:739 msgid "Default Resolution" msgstr "ნაგულისხმები გარჩევადობ" #: piper/ratbagd.py:740 msgid "Cycle Profile Up" msgstr "პროფილის აწევა ციკლურად" #: piper/ratbagd.py:741 msgid "Cycle Profile Down" msgstr "პროფილის დაწევა ციკლურად" #: piper/ratbagd.py:742 msgid "Profile Up" msgstr "პროფილის აწევა" #: piper/ratbagd.py:743 msgid "Profile Down" msgstr "პროფილის დაწევა" #: piper/ratbagd.py:744 msgid "Second Mode" msgstr "მეორე რეჟიმი" #: piper/ratbagd.py:745 msgid "Battery Level" msgstr "ელემენტის მუხტის დონე" #. Translators: this is used when there is no macro to preview. #: piper/ratbagd.py:895 data/ui/ButtonDialog.ui:106 data/ui/ButtonDialog.ui:187 msgid "None" msgstr "არაფერი" #. Translators: the LED is off. #: piper/ratbagd.py:977 data/ui/LedDialog.ui:395 msgid "Off" msgstr "გამორთული" #. Translators: the LED has a single, solid color. #: piper/ratbagd.py:979 data/ui/LedDialog.ui:66 msgid "Solid" msgstr "მყარი" #. Translators: the LED is cycling between red, green and blue. #: piper/ratbagd.py:981 data/ui/LedDialog.ui:189 msgid "Cycle" msgstr "ციკლი" #. Translators: the LED's is pulsating a single color on different #. brightnesses. #: piper/ratbagd.py:984 data/ui/LedDialog.ui:355 msgid "Breathing" msgstr "პულსაცია" #: piper/window.py:42 msgid "Cannot connect to ratbagd" msgstr "შეცდომა ratbagd-თან მიერთებისას" #: piper/window.py:43 msgid "" "Please make sure ratbagd is running and your user is in the required group" msgstr "" "დარწმუნდით, რომ ratbagd გაშვებულია და თქვენი მომხმარებელი შესაბამის ჯგუფში " "იმყოფება" #: piper/window.py:46 msgid "Incompatible ratbagd API version (required: {}, provided: {})" msgstr "Ratbagd-ის API-ის შეუთავსებელი ვერსია (საჭიროა: {}, მოწოდებულია: {})" #: piper/window.py:47 msgid "Please update both piper and libratbag to the latest versions" msgstr "ორივე, piper და libratbag უახლეს ვერსიებამდე გაანახლეთ" #: piper/window.py:61 piper/window.py:115 msgid "Cannot find any devices" msgstr "მოწყობილობები აღმოჩენილი არაა" #: piper/window.py:62 piper/window.py:116 msgid "Please make sure your device is supported and plugged in" msgstr "დარწმუნდით, რომ მოწყობილობა შეერთებული და მხარდაჭერილია" #: piper/window.py:74 msgid "There are unapplied changes. Are you sure you want to quit?" msgstr "" "არსებობს გადაუტარებელი ცვლილებები. დარწმუნებული ბრძანდებით, რომ გნებავთ, " "გახვიდეთ?" #: piper/window.py:83 msgid "Ooops. ratbagd has disappeared" msgstr "ვაი, ratbagd გაუჩინარდა" #: piper/window.py:84 msgid "Please restart Piper" msgstr "გადატვირთეთ Piper" #. The current device disconnected, which can only happen from the #. mouse perspective as we'd otherwise be in the welcome screen with #. more than one device remaining. Hence, we display the error #. perspective. #: piper/window.py:107 msgid "Your device disconnected!" msgstr "თქვენი მოწყობილობა გამოერთებულია!" #: piper/window.py:108 msgid "Please make sure your device is plugged in" msgstr "დარწმუნდით, რომ მოწყობილობა შეერთებულია" #: piper/window.py:147 msgid "Cannot display device SVG" msgstr "მოწყობილობის SVG-ის ჩვენების შეცდომა" #: piper/window.py:154 msgid "Newer version of ratbagd required" msgstr "აუცილებელია ratbagd-ის უფრო ახალი ვერსია" #: piper/window.py:155 msgid "Please update to the latest available version" msgstr "განაახლეთ უახლეს ხელმისაწვდომ ვერსიამდე" #: piper/window.py:157 msgid "Unknown exception occurred" msgstr "ნაპოვნია უცნობი გამონაკლისი" #: data/ui/AboutDialog.ui.in:10 msgid "Version: @version@" msgstr "ვერსია: @version@" #: data/ui/AboutDialog.ui.in:12 msgid "Visit Piper on GitHub" msgstr "იპოვეთ Piper-ი GitHub-ზე" #: data/ui/AboutDialog.ui.in:13 msgid "translator-credits" msgstr "მთარგმნელის შესახებ" #: data/ui/ButtonDialog.ui:65 msgid "Search for a button mapping" msgstr "ღილაკის მიბმის მოძებნა" #: data/ui/ButtonDialog.ui:91 msgid "Capture a macro for this button" msgstr "ამ ღილაკისთვის მაკროს ჩაჭერა" #: data/ui/ButtonDialog.ui:104 msgid "The currently set macro" msgstr "ამჟამად დაყენებული მაკრო" #: data/ui/ButtonDialog.ui:129 msgid "Send keystroke" msgstr "ღილაკების კომბინაციის გაგზავნა" #: data/ui/ButtonDialog.ui:169 msgid "Enter a new key sequence for the macro." msgstr "მაკროსთვის ახალი ღილაკების მიმდევრობის შეყვანა აუცილებელია." #: data/ui/ButtonDialog.ui:235 msgid "Set the device’s handedness." msgstr "მოწყობილობის ხელის მხრის დაყენება." #: data/ui/ButtonDialog.ui:253 msgid "" "This allows you to swap the order of the primary mouse buttons. In left-" "handed mode, the physical left mouse button generates a right mouse click " "and vice versa." msgstr "" "ეს საშუალებას გალევთ თაგუნას ძირითადი ღილაკების მიმდევრობა შეცვალოთ. ცაციის " "რეჟიმში თაგუნას ფიზიკური მარცხენა ღილაკი მარჯვენას წკაპს აგენერირებს და " "პირიქით." #: data/ui/ButtonDialog.ui:273 msgid "Left Handed" msgstr "ცაცია" #: data/ui/ButtonDialog.ui:278 msgid "The left mouse button generates a left mouse click" msgstr "თაგუნას მარცხენა ღილაკი თაგუნას მარცხენა ღილაკს აგენერირებს" #: data/ui/ButtonDialog.ui:292 msgid "Right Handed" msgstr "მარჯვენახელიანი" #: data/ui/ButtonDialog.ui:297 msgid "The left mouse button generates a right mouse click" msgstr "თაგუნას მარცხენა ღილაკი თაგუნას მარჯვენა ღილაკს აგენერირებს" #: data/ui/ButtonDialog.ui:337 data/ui/LedDialog.ui:414 msgid "Cancel" msgstr "გაუქმება" #: data/ui/ButtonDialog.ui:339 data/ui/LedDialog.ui:418 msgid "Ignore any changes made" msgstr "ცვლილებების იგნორი" #: data/ui/ButtonDialog.ui:345 data/ui/LedDialog.ui:430 #: data/ui/MousePerspective.ui:132 msgid "Apply" msgstr "გამოყენება" #: data/ui/ButtonDialog.ui:348 data/ui/LedDialog.ui:435 msgid "Apply any changes made" msgstr "ცვლილებების გადატარება" #: data/ui/ButtonDialog.ui:388 msgid "No button mapping found" msgstr "ღილაკის მიბმა აღმოჩენილი არაა" #: data/ui/ButtonDialog.ui:404 msgid "Try a different search" msgstr "სცადეთ სხვა ძებნა" #: data/ui/ErrorPerspective.ui:16 msgid "Here, rodent, rodent, rodent…" msgstr "აქეთ, თაგუნა, თაგუნა, თაგუნა…" #: data/ui/ErrorPerspective.ui:69 msgid "Uh Oh! Something went wrong…" msgstr "რაღაც არასწორად წავიდა…" #: data/ui/LedDialog.ui:58 data/ui/LedDialog.ui:209 msgid "Choose a color for the LED" msgstr "აირჩიეთ LED-ის ფერი" #: data/ui/LedDialog.ui:90 data/ui/LedDialog.ui:257 msgid "Choose a brightness for the LED" msgstr "აირჩიეთ LED-ის სიკაშკაშე" #: data/ui/LedDialog.ui:104 data/ui/LedDialog.ui:270 msgid "Brightness" msgstr "სიკაშკაშე" #: data/ui/LedDialog.ui:135 data/ui/LedDialog.ui:301 msgid "Choose an effect duration for the LED" msgstr "აირჩიეთ LED-ის ეფექტის ხანგრძლივობა" #: data/ui/LedDialog.ui:153 data/ui/LedDialog.ui:319 msgid "ms" msgstr "მწმ" #: data/ui/LedDialog.ui:175 data/ui/LedDialog.ui:341 msgid "Effect duration" msgstr "ეფექტის ხანგრძლივობა" #: data/ui/LedDialog.ui:212 msgid "Pick a Color for the LED" msgstr "აირჩიეთ LED-ის ფერი" #: data/ui/LedDialog.ui:226 msgid "Color" msgstr "ფერი" #: data/ui/LedDialog.ui:380 msgid "This LED is off" msgstr "ეს LED გამორთულია" #: data/ui/MousePerspective.ui:44 msgid "Something went wrong. The device has been reset to a previous state." msgstr "რაღაც არასწორად წავიდა. მოწყობილობა წინა მდგომარეობაზე დაბრუნდა." #: data/ui/MousePerspective.ui:101 msgid "Select another profile" msgstr "აირჩიეთ სხვა პროფილი" #: data/ui/MousePerspective.ui:126 msgid "Commit the changes to the device" msgstr "ცვლილებების მოწყობილობაზე გადაცემა" #: data/ui/MousePerspective.ui:170 msgid "Click to switch to another profile" msgstr "დააწკაპუნეთ სხვა პროფილზე გადასართავად" #: data/ui/MousePerspective.ui:185 msgid "Add profile" msgstr "პროფილის დამატება" #: data/ui/MousePerspective.ui:189 msgid "Add a new profile to the device" msgstr "მოწყობილობაზე ახალი პროფილის დამატება" #: data/ui/OptionButton.ui:9 msgid "Open the configuration dialog" msgstr "მორგების ფანჯრის გახსნა" #: data/ui/ProfileRow.ui:16 msgid "Remove this profile from the device" msgstr "მოწყობილობიდან ამ პროფილის წაშლა" #. Translators: this is used to indicate the active resolution. #: data/ui/ResolutionRow.ui:37 msgid "active" msgstr "აქტიური" #: data/ui/ResolutionRow.ui:69 msgid "Set this resolution's dpi" msgstr "გადახედვის გარჩევადობა DPI დაყენება" #: data/ui/ResolutionRow.ui:95 msgid "Disable" msgstr "გამორთვა" #: data/ui/ResolutionRow.ui:101 msgid "Disable this resolution" msgstr "ამ გარჩევადობის გამორთვა" #: data/ui/ResolutionRow.ui:112 msgid "Set active" msgstr "აქტიურად მონიშვნა" #: data/ui/ResolutionRow.ui:117 msgid "Set this resolution as active" msgstr "ამ გაფართოების აქტიურად მონიშვნა" #. Translators: the rate at which the device reports movement. #: data/ui/ResolutionsPage.ui:43 msgid "Report rate" msgstr "ანგარიშის სიხშირეა" #: data/ui/ResolutionsPage.ui:60 msgid "Change the profile’s report rate" msgstr "პროფილის ანგარიშის სიხშირის შეცვლა" #: data/ui/ResolutionsPage.ui:136 msgid "Hz" msgstr "ჰც" #. Translators: the sensitivity of the device's sensor. #: data/ui/ResolutionsPage.ui:156 msgid "Sensitivity" msgstr "მგრძნობიარობა" #: data/ui/ResolutionsPage.ui:205 msgid "Add a new resolution to the profile" msgstr "პროფილზე ახალი გაფართოების დამატება" #: data/ui/WelcomePerspective.ui:20 msgid "Welcome" msgstr "კეთილი იყოს თქვენი მობრძანება" #: data/ui/WelcomePerspective.ui:38 msgctxt "A subtitle under the \"Welcome\" title." msgid "Select a device to configure it" msgstr "აირჩიეთ მოსარგები მოწყობილობა" #: data/ui/WelcomePerspective.ui:89 msgctxt "A tooltip over the list of devices." msgid "Select a device to configure it" msgstr "აირჩიეთ მოსარგები მოწყობილობა" #: data/ui/WelcomePerspective.ui:119 msgid "Select a Device" msgstr "აირჩიეთ მოწყობილობა" #: data/ui/Window.ui:8 msgid "_About Piper" msgstr "Piper-ის _შესახებ" piper-0.8/po/meson.build000066400000000000000000000000461467456234500153000ustar00rootroot00000000000000i18n.gettext('piper', preset: 'glib') piper-0.8/po/nl.po000066400000000000000000000357671467456234500141310ustar00rootroot00000000000000# Dutch Piper translation # Copyright (C) 2017 Jente Hidskes # This file is distributed under the same license as the piper package. # Jente Hidskes , 2017. # msgid "" msgstr "" "Project-Id-Version: piper\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2023-04-14 12:32+0200\n" "PO-Revision-Date: 2023-04-14 12:36+0200\n" "Last-Translator: Heimen Stoffels \n" "Language-Team: Dutch <>\n" "Language: nl_NL\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Generator: Poedit 3.2.2\n" #: data/org.freedesktop.Piper.desktop.in:3 msgid "Piper" msgstr "Piper" #: data/org.freedesktop.Piper.desktop.in:4 msgid "Configurable mouse configuration utility" msgstr "Uitgebreid hulpmiddel voor het instellen van muizen" #. Translators: Search terms to find this application. Do NOT translate or localize the semicolons! The list MUST also end with a semicolon! #: data/org.freedesktop.Piper.desktop.in:12 msgid "gaming;configuration;mouse;mice;" msgstr "gaming;instellen;muis;muizen;" #: data/org.freedesktop.Piper.appdata.xml.in.in:8 msgid "Gaming mouse configuration utility" msgstr "Uitgebreid hulpmiddel voor het instellen van gamingmuizen" #: data/org.freedesktop.Piper.appdata.xml.in.in:10 msgid "" "Piper is a graphical user interface to configure gaming mice. Configuration " "options include changing the resolution (DPI) of the mouse, adding and " "removing profiles, setting LED colors and changing button behaviors." msgstr "" "Piper is een grafische toepassing voor het instellen van gamingmuizen. Zo " "kun je onder meer de resolutie (dpi) van je muis instellen, profielen " "toevoegen en verwijderen en ledkleuren en knoptoewijzingen aanpassen." #: data/org.freedesktop.Piper.appdata.xml.in.in:16 msgid "" "Piper requires libratbag’s ratbagd, the daemon to actually communicate with " "the mice. Piper is merely a front end to ratbagd, ratbagd must be installed " "and running when Piper is launched." msgstr "" "Piper is afhankelijk van libratbags ratbagd, de achtergronddienst die " "daadwerkelijk met de muis communiceert. Piper is slechts een grafische schil " "hieromheen. ratbagd dient dus geïnstalleerd en actief te zijn voordat je " "Piper opstart." #: data/org.freedesktop.Piper.appdata.xml.in.in:27 msgid "The button configuraton page" msgstr "De knopvoorkeurenpagina" #: data/org.freedesktop.Piper.appdata.xml.in.in:31 msgid "The LED configuraton page" msgstr "De ledvoorkeurenpagina" #: data/org.freedesktop.Piper.appdata.xml.in.in:35 msgid "The resolution configuraton page" msgstr "De resolutievoorkeurenpagina" #: piper/buttondialog.py:156 msgid "Button mapping" msgstr "Knopvoorkeuren" #: piper/buttondialog.py:172 msgid "Special mapping" msgstr "Speciale voorkeuren" #: piper/buttondialog.py:182 data/ui/ResolutionRow.ui:95 msgid "Disable" msgstr "Uitschakelen" #: piper/buttondialog.py:182 msgid "Other" msgstr "Overig" #. Translators: the {} will be replaced with the button index, e.g. #. "Button 1 click". #: piper/buttondialog.py:257 piper/buttonspage.py:105 msgid "Button {} click" msgstr "{} muisklik" #: piper/buttonspage.py:109 msgid "Macro: {}" msgstr "Macro: {}" #: piper/buttonspage.py:111 msgid "Key: {}" msgstr "Toets: {}" #. Translators: the button is turned disabled, e.g. off. #: piper/buttonspage.py:114 msgid "Disabled" msgstr "Uitgeschakeld" #. Translators: the button has an unknown function. #: piper/buttonspage.py:117 piper/ratbagd.py:868 msgid "Unknown" msgstr "Onbekend" #: piper/buttonspage.py:131 msgid "Configure button {}" msgstr "{}knop instellen" #: piper/mouseperspective.py:120 data/ui/ResolutionsPage.ui:78 msgid "Resolutions" msgstr "Resoluties" #: piper/mouseperspective.py:124 msgid "Buttons" msgstr "Knoppen" #: piper/mouseperspective.py:127 msgid "LEDs" msgstr "Ledverlichting" #: piper/mouseperspective.py:138 msgid "Advanced" msgstr "Geavanceerd" #: piper/ratbagd.py:858 msgid "Left mouse button click" msgstr "Linkermuisklik" #: piper/ratbagd.py:859 msgid "Right mouse button click" msgstr "Rechtermuisklik" #: piper/ratbagd.py:860 msgid "Middle mouse button click" msgstr "Middelste muisklik" #: piper/ratbagd.py:861 msgid "Backward" msgstr "Vorige" #: piper/ratbagd.py:862 msgid "Forward" msgstr "Volgende" #: piper/ratbagd.py:867 msgid "Invalid" msgstr "Ongeldig" #: piper/ratbagd.py:869 msgid "Doubleclick" msgstr "Dubbelklikken" #: piper/ratbagd.py:870 msgid "Wheel Left" msgstr "Muiswiel naar links" #: piper/ratbagd.py:871 msgid "Wheel Right" msgstr "Muiswiel naar rechts" #: piper/ratbagd.py:872 msgid "Wheel Up" msgstr "Muiswiel omhoog" #: piper/ratbagd.py:873 msgid "Wheel Down" msgstr "Muiswiel omlaag" #: piper/ratbagd.py:874 msgid "Ratchet Mode" msgstr "Vrij scrollen" #: piper/ratbagd.py:875 msgid "Cycle Resolution Up" msgstr "Volgende resolutie (cyclisch)" #: piper/ratbagd.py:876 msgid "Cycle Resolution Down" msgstr "Vorige resolutie (cyclisch)" #: piper/ratbagd.py:877 msgid "Resolution Up" msgstr "Volgende resolutie" #: piper/ratbagd.py:878 msgid "Resolution Down" msgstr "Vorige resolutie" #: piper/ratbagd.py:879 msgid "Resolution Switch" msgstr "Overschakelen naar andere resolutie" #: piper/ratbagd.py:880 msgid "Default Resolution" msgstr "Standaardresolutie" #: piper/ratbagd.py:881 msgid "Cycle Profile Up" msgstr "Volgend profiel (cyclisch)" #: piper/ratbagd.py:882 msgid "Cycle Profile Down" msgstr "Vorig profiel (cyclisch)" #: piper/ratbagd.py:883 msgid "Profile Up" msgstr "Volgend profiel" #: piper/ratbagd.py:884 msgid "Profile Down" msgstr "Vorig profiel" #: piper/ratbagd.py:885 msgid "Second Mode" msgstr "Tweede modus" #: piper/ratbagd.py:886 msgid "Battery Level" msgstr "Accu-/Batterijniveau" #. Translators: this is used when there is no macro to preview. #: piper/ratbagd.py:1032 data/ui/ButtonDialog.ui:100 #: data/ui/ButtonDialog.ui:181 msgid "None" msgstr "Geen" #. Translators: the LED is off. #: piper/ratbagd.py:1108 data/ui/LedDialog.ui:368 msgid "Off" msgstr "Uit" #. Translators: the LED has a single, solid color. #: piper/ratbagd.py:1110 data/ui/LedDialog.ui:59 msgid "Solid" msgstr "Eén kleur" #. Translators: the LED is cycling between red, green and blue. #: piper/ratbagd.py:1112 data/ui/LedDialog.ui:172 msgid "Cycle" msgstr "Meerdere kleuren" #. Translators: the LED's is pulsating a single color on different #. brightnesses. #: piper/ratbagd.py:1115 data/ui/LedDialog.ui:328 msgid "Breathing" msgstr "Pulseren" #: piper/window.py:52 msgid "Cannot connect to ratbagd" msgstr "Kan niet verbinden met ratbagd" #: piper/window.py:54 msgid "" "Please make sure ratbagd is running and your user is in the required group" msgstr "" "Zorg er voor dat ratbagd uitgevoerd wordt en dat je gebruikersaccount " "onderdeel van de vereiste groep is" #: piper/window.py:61 msgid "Incompatible ratbagd API version (required: {}, provided: {})" msgstr "Incompatibele ratbagd api-versie (vereist: {} - beschikbaar: {})" #: piper/window.py:65 msgid "Please update both piper and libratbag to the latest versions" msgstr "Werk zowel piper als libratbag bij naar de nieuwste versie" #: piper/window.py:81 piper/window.py:146 msgid "Cannot find any devices" msgstr "Kan geen apparaten vinden" #: piper/window.py:82 piper/window.py:147 msgid "Please make sure your device is supported and plugged in" msgstr "Zorg er voor dat je apparaat ondersteund wordt en verbonden is" #: piper/window.py:97 msgid "There are unapplied changes. Are you sure you want to quit?" msgstr "" "Er zijn wijzigingen aangebracht, maar deze zijn niet toegepast. Weet je " "zeker dat je wilt afsluiten?" #: piper/window.py:111 msgid "Ooops. ratbagd has disappeared" msgstr "Oeps, ratbagd is onverwachts afgesloten" #: piper/window.py:111 msgid "Please restart Piper" msgstr "Herstart Piper" #: piper/window.py:136 msgid "Your device disconnected!" msgstr "Je apparaat is niet meer verbonden!" #: piper/window.py:137 msgid "Please make sure your device is plugged in" msgstr "Zorg er voor dat je apparaat verbonden is" #: piper/window.py:183 msgid "Cannot display device SVG" msgstr "Kan de svg van dit apparaat niet tonen" #: piper/window.py:191 msgid "Newer version of ratbagd required" msgstr "Nieuwere versie van ratbagd vereist" #: piper/window.py:192 msgid "Please update to the latest available version" msgstr "Installeer de nieuwste versie" #: piper/window.py:196 msgid "Unknown exception occurred" msgstr "Er is een onbekende fout opgetreden" #: data/ui/AboutDialog.ui.in:12 msgid "Visit Piper on GitHub" msgstr "GitHub-pagina openen" #: data/ui/AboutDialog.ui.in:13 msgid "translator-credits" msgstr "Heimen Stoffels " #. Translators: the rate at which the device reports movement. #: data/ui/AdvancedPage.ui:33 msgid "Report rate" msgstr "Rapportagesnelheid" #: data/ui/AdvancedPage.ui:50 msgid "Change the profile’s report rate" msgstr "Pas de rapportagesnelheid van dit profiel aan" #: data/ui/AdvancedPage.ui:125 msgid "Hz" msgstr "Hz" #: data/ui/AdvancedPage.ui:154 msgid "Debounce time" msgstr "Vertraging" #: data/ui/AdvancedPage.ui:183 data/ui/LedDialog.ui:138 #: data/ui/LedDialog.ui:294 msgid "ms" msgstr "ms" #: data/ui/AdvancedPage.ui:212 msgid "Angle snapping" msgstr "Stabiele muisverplaatsing" #: data/ui/ButtonDialog.ui:59 msgid "Search for a button mapping" msgstr "Zoeken naar knoptoewijzing" #: data/ui/ButtonDialog.ui:85 msgid "Capture a macro for this button" msgstr "Macro vastleggen voor deze knop" #: data/ui/ButtonDialog.ui:98 msgid "The currently set macro" msgstr "De momenteel ingestelde macro" #: data/ui/ButtonDialog.ui:123 msgid "Send keystroke" msgstr "Toetsencombinatie versturen" #: data/ui/ButtonDialog.ui:163 msgid "Enter a new key sequence for the macro." msgstr "Druk op een nieuwe toetsencombinatie." #: data/ui/ButtonDialog.ui:229 msgid "Set the device’s handedness." msgstr "Stel links- of rechthandigheid in." #: data/ui/ButtonDialog.ui:247 msgid "" "This allows you to swap the order of the primary mouse buttons. In left-" "handed mode, the physical left mouse button generates a right mouse click " "and vice versa." msgstr "" "Hiermee kun je de volgorde van de primaire muisknoppen omwisselen. In de " "linkshandige modus zorgt de linkermuisknop voor een rechtermuisklik en vice " "versa." #: data/ui/ButtonDialog.ui:267 msgid "Left Handed" msgstr "Linkshandig" #: data/ui/ButtonDialog.ui:272 msgid "The left mouse button generates a left mouse click" msgstr "De linkermuisknop zorgt voor een linkermuisklik" #: data/ui/ButtonDialog.ui:286 msgid "Right Handed" msgstr "Rechtshandig" #: data/ui/ButtonDialog.ui:291 msgid "The left mouse button generates a right mouse click" msgstr "De linkermuisknop zorgt voor een rechtermuisklik" #: data/ui/ButtonDialog.ui:331 data/ui/LedDialog.ui:394 msgid "Cancel" msgstr "Annuleren" #: data/ui/ButtonDialog.ui:333 data/ui/LedDialog.ui:398 msgid "Ignore any changes made" msgstr "Alle wijzigingen negeren" #: data/ui/ButtonDialog.ui:339 data/ui/LedDialog.ui:403 #: data/ui/MousePerspective.ui:187 msgid "Apply" msgstr "Toepassen" #: data/ui/ButtonDialog.ui:342 data/ui/LedDialog.ui:408 msgid "Apply any changes made" msgstr "Alle wijzigingen toepassen" #: data/ui/ButtonDialog.ui:382 msgid "No button mapping found" msgstr "Geen knoptoewijzingen ingesteld" #: data/ui/ButtonDialog.ui:398 msgid "Try a different search" msgstr "Probeer een andere zoekopdracht" #: data/ui/ErrorPerspective.ui:16 msgid "Here, rodent, rodent, rodent…" msgstr "Hier, poesie, poesie, poesie…" #: data/ui/ErrorPerspective.ui:69 msgid "Uh Oh! Something went wrong…" msgstr "Oeps, er is iets misgegaan…" #: data/ui/LedDialog.ui:51 data/ui/LedDialog.ui:192 msgid "Choose a color for the LED" msgstr "Kies een ledkleur" #: data/ui/LedDialog.ui:78 data/ui/LedDialog.ui:235 msgid "Choose a brightness for the LED" msgstr "Kies het ledhelderheidsniveau" #: data/ui/LedDialog.ui:92 data/ui/LedDialog.ui:248 msgid "Brightness" msgstr "Helderheid" #: data/ui/LedDialog.ui:120 data/ui/LedDialog.ui:276 msgid "Choose an effect duration for the LED" msgstr "Kies een ledeffectsnelheid" #: data/ui/LedDialog.ui:158 data/ui/LedDialog.ui:314 msgid "Effect duration" msgstr "Effectsnelheid" #: data/ui/LedDialog.ui:195 msgid "Pick a Color for the LED" msgstr "Kies een ledkleur" #: data/ui/LedDialog.ui:209 msgid "Color" msgstr "Kleur" #: data/ui/LedDialog.ui:355 msgid "This LED is off" msgstr "Deze led is uitgeschakeld" #: data/ui/MousePerspective.ui:43 msgid "Something went wrong. The device has been reset to a previous state." msgstr "" "Er is iets misgegaan - het apparaat is teruggezet naar de vorige staat." #: data/ui/MousePerspective.ui:116 msgid "Click to switch to another profile" msgstr "Klik om van profiel te veranderen" #: data/ui/MousePerspective.ui:131 msgid "Add profile" msgstr "Profiel toevoegen" #: data/ui/MousePerspective.ui:135 msgid "Add a new profile to the device" msgstr "Voeg een nieuw profiel toe aan het apparaat" #: data/ui/MousePerspective.ui:163 msgid "Select another profile" msgstr "Kies een ander profiel" #: data/ui/MousePerspective.ui:181 msgid "Commit the changes to the device" msgstr "Pas de wijzigingen toe op het apparaat" #: data/ui/OptionButton.ui:9 msgid "Open the configuration dialog" msgstr "Open de voorkeuren" #: data/ui/ProfileRow.ui:16 msgid "Remove this profile from the device" msgstr "Verwijder dit profiel van het apparaat" #. Translators: this is used to indicate the active resolution. #: data/ui/ResolutionRow.ui:37 msgid "active" msgstr "Actief" #: data/ui/ResolutionRow.ui:69 msgid "Set this resolution's dpi" msgstr "Stel de dpi van deze resolutie in" #: data/ui/ResolutionRow.ui:101 msgid "Disable this resolution" msgstr "Schakel deze resolutie uit" #: data/ui/ResolutionRow.ui:112 msgid "Set active" msgstr "Instellen als actief" #: data/ui/ResolutionRow.ui:117 msgid "Set this resolution as active" msgstr "Stel deze resolutie in als actief" #: data/ui/ResolutionsPage.ui:45 msgid "Add a new resolution to the profile" msgstr "Voeg een nieuwe resolutie toe aan het profiel" #: data/ui/WelcomePerspective.ui:20 msgid "Welcome" msgstr "Welkom" #: data/ui/WelcomePerspective.ui:38 msgctxt "A subtitle under the \"Welcome\" title." msgid "Select a device to configure it" msgstr "Kies een in te stellen apparaat" #: data/ui/WelcomePerspective.ui:88 msgctxt "A tooltip over the list of devices." msgid "Select a device to configure it" msgstr "Kies een in te stellen apparaat" #: data/ui/WelcomePerspective.ui:118 msgid "Select a Device" msgstr "Kies een apparaat" #: data/ui/Window.ui:8 msgid "_About Piper" msgstr "_Over Piper" #~ msgid "org.freedesktop.Piper" #~ msgstr "org.freedesktop.Piper" #~ msgid "Version: @version@" #~ msgstr "Versie: @version@" #~ msgid "Press Escape to cancel or Return to accept." #~ msgstr "Druk op Escape om af te breken of op Enter om te accepteren." #~ msgid "Quit" #~ msgstr "Afsluiten" #~ msgid "Sensitivity" #~ msgstr "Gevoeligheid" #~ msgid "Profile {}" #~ msgstr "Profiel {}" #~ msgid "_Quit" #~ msgstr "_Afsluiten" #~ msgid "Failed to commit changes to the device" #~ msgstr "Fout bij het toepassen van de veranderingen op het apparaat" #~ msgid "Remove this resolution from the profile" #~ msgstr "Verwijder deze resolutie uit het profiel" piper-0.8/po/pl.po000066400000000000000000000362331467456234500141200ustar00rootroot00000000000000# Polish translation for piper. # Copyright © 2017-2020 the piper authors. # This file is distributed under the same license as the piper package. # Piotr Drąg , 2017-2020. # Aviary.pl , 2017-2020. # msgid "" msgstr "" "Project-Id-Version: piper\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2020-01-27 21:28+0100\n" "PO-Revision-Date: 2020-01-24 15:22+0100\n" "Last-Translator: Piotr Drąg \n" "Language-Team: Polish \n" "Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 " "|| n%100>=20) ? 1 : 2);\n" #: data/org.freedesktop.Piper.desktop.in:3 #: data/org.freedesktop.Piper.appdata.xml.in.in:7 msgid "Piper" msgstr "Piper" #: data/org.freedesktop.Piper.desktop.in:4 #: data/org.freedesktop.Piper.appdata.xml.in.in:8 msgid "Configurable mouse configuration utility" msgstr "Konfigurowalne narzędzie do konfiguracji myszy" #. Translators: Do NOT translate or transliterate this text (this is an icon file name)! #: data/org.freedesktop.Piper.desktop.in:7 msgid "org.freedesktop.Piper" msgstr "org.freedesktop.Piper" #. Translators: Search terms to find this application. Do NOT translate or localize the semicolons! The list MUST also end with a semicolon! #: data/org.freedesktop.Piper.desktop.in:12 msgid "gaming;configuration;mouse;mice;" msgstr "" "gry;gra;granie;konfiguracja;ustawienia;opcje;preferencje;mysz;myszy;myszka;" "myszki;gryzoń;" #: data/org.freedesktop.Piper.appdata.xml.in.in:10 msgid "" "Piper is a graphical user interface to configure gaming mice. Configuration " "options include changing the resolution (DPI) of the mouse, adding and " "removing profiles, setting LED colors and changing button behaviors." msgstr "" "Piper to graficzny interfejs użytkownika do konfiguracji myszy do gier " "komputerowych. Można między innymi zmieniać rozdzielczość (DPI) myszy, " "dodawać i usuwać profile, ustawiać kolory diod LED i zmieniać zachowanie " "przycisków." #: data/org.freedesktop.Piper.appdata.xml.in.in:16 msgid "" "Piper requires libratbag’s ratbagd, the daemon to actually communicate with " "the mice. Piper is merely a front end to ratbagd, ratbagd must be installed " "and running when Piper is launched." msgstr "" "Piper wymaga ratbagd biblioteki libratbag, usługi do komunikacji z myszą. " "Piper to tylko interfejs dla usługi ratbagd, która musi być zainstalowana " "i uruchomiona przed włączeniem programu Piper." #: data/org.freedesktop.Piper.appdata.xml.in.in:33 msgid "The button configuraton page" msgstr "Strona konfiguracji przycisków" #: data/org.freedesktop.Piper.appdata.xml.in.in:37 msgid "The LED configuraton page" msgstr "Strona konfiguracji diod LED" #: data/org.freedesktop.Piper.appdata.xml.in.in:41 msgid "The resolution configuraton page" msgstr "Strona konfiguracji rozdzielczości" #. Translators: section header for mapping one button's click to another. #: piper/buttondialog.py:141 msgid "Button mapping" msgstr "Mapowanie przycisku" #. Translators: section header for assigning special functions to buttons. #: piper/buttondialog.py:150 msgid "Special mapping" msgstr "Mapowanie specjalne" #. Translators: the {} will be replaced with the button index, e.g. #. "Button 1 click". #: piper/buttondialog.py:222 piper/buttonspage.py:90 msgid "Button {} click" msgstr "Kliknięcie {}. przyciskiem" #: piper/buttonspage.py:94 msgid "Macro: {}" msgstr "Makro: {}" #. Translators: the button is turned disabled, e.g. off. #: piper/buttonspage.py:97 msgid "Disabled" msgstr "Wyłączone" #. Translators: the button has an unknown function. #: piper/buttonspage.py:100 piper/ratbagd.py:665 msgid "Unknown" msgstr "Nieznane" #: piper/buttonspage.py:108 msgid "Configure button {}" msgstr "Konfiguracja {}. przycisku" #: piper/mouseperspective.py:90 data/ui/ResolutionsPage.ui:209 msgid "Resolutions" msgstr "Rozdzielczości" #: piper/mouseperspective.py:92 msgid "Buttons" msgstr "Przyciski" #: piper/mouseperspective.py:94 msgid "LEDs" msgstr "Diody LED" #: piper/ratbagd.py:655 msgid "Left mouse button click" msgstr "Kliknięcie lewym przyciskiem myszy" #: piper/ratbagd.py:656 msgid "Right mouse button click" msgstr "Kliknięcie prawym przyciskiem myszy" #: piper/ratbagd.py:657 msgid "Middle mouse button click" msgstr "Kliknięcie środkowym przyciskiem myszy" #: piper/ratbagd.py:658 msgid "Backward" msgstr "Wstecz" #: piper/ratbagd.py:659 msgid "Forward" msgstr "Dalej" #: piper/ratbagd.py:664 msgid "Invalid" msgstr "Nieprawidłowe" #: piper/ratbagd.py:666 msgid "Doubleclick" msgstr "Podwójne kliknięcie" #: piper/ratbagd.py:667 msgid "Wheel Left" msgstr "Kółko w lewo" #: piper/ratbagd.py:668 msgid "Wheel Right" msgstr "Kółko w prawo" #: piper/ratbagd.py:669 msgid "Wheel Up" msgstr "Kółko w górę" #: piper/ratbagd.py:670 msgid "Wheel Down" msgstr "Kółko w dół" #: piper/ratbagd.py:671 msgid "Ratchet Mode" msgstr "Tryb zapadkowy" #: piper/ratbagd.py:672 msgid "Cycle Resolution Up" msgstr "Przewija rozdzielczość w górę" #: piper/ratbagd.py:673 msgid "Cycle Resolution Down" msgstr "Przewija rozdzielczość w dół" #: piper/ratbagd.py:674 msgid "Resolution Up" msgstr "Rozdzielczość w górę" #: piper/ratbagd.py:675 msgid "Resolution Down" msgstr "Rozdzielczość w dół" #: piper/ratbagd.py:676 msgid "Resolution Switch" msgstr "Przełączenie rozdzielczości" #: piper/ratbagd.py:677 msgid "Default Resolution" msgstr "Domyślna rozdzielczość" #: piper/ratbagd.py:678 msgid "Cycle Profile Up" msgstr "Przewija profil w górę" #: piper/ratbagd.py:679 msgid "Cycle Profile Down" msgstr "Przewija profil w dół" #: piper/ratbagd.py:680 msgid "Profile Up" msgstr "Profil w górę" #: piper/ratbagd.py:681 msgid "Profile Down" msgstr "Profil w dół" #: piper/ratbagd.py:682 msgid "Second Mode" msgstr "Drugi poziom" #: piper/ratbagd.py:683 msgid "Battery Level" msgstr "Poziom naładowania akumulatora" #. Translators: this is used when there is no macro to preview. #: piper/ratbagd.py:813 data/ui/ButtonDialog.ui:106 data/ui/ButtonDialog.ui:187 msgid "None" msgstr "Brak" #. Translators: the LED is off. #: piper/ratbagd.py:895 data/ui/LedDialog.ui:395 msgid "Off" msgstr "Wyłączone" #. Translators: the LED has a single, solid color. #: piper/ratbagd.py:897 data/ui/LedDialog.ui:66 msgid "Solid" msgstr "Jeden kolor" #. Translators: the LED is cycling between red, green and blue. #: piper/ratbagd.py:899 data/ui/LedDialog.ui:189 msgid "Cycle" msgstr "Zmienny kolor" #. Translators: the LED's is pulsating a single color on different #. brightnesses. #: piper/ratbagd.py:902 data/ui/LedDialog.ui:355 msgid "Breathing" msgstr "Pulsujący kolor" #: piper/window.py:54 msgid "Cannot connect to ratbagd" msgstr "Nie można połączyć z usługą ratbagd" #: piper/window.py:55 msgid "" "Please make sure ratbagd is running and your user is in the required group" msgstr "" "Proszę się upewnić, że usługa ratbagd jest uruchomiona, a obecny użytkownik " "jest w wymaganej grupie" #: piper/window.py:58 msgid "Incompatible ratbagd API version (required: {}, provided: {})" msgstr "Niezgodna wersja API usługi ratbagd (wymagana: {}, dostarczona: {})" #: piper/window.py:59 msgid "Please update both piper and libratbag to the latest versions" msgstr "" "Proszę zaktualizować program Piper i usługę libratbag do najnowszych wersji" #: piper/window.py:73 piper/window.py:127 msgid "Cannot find any devices" msgstr "Nie można odnaleźć żadnego urządzenia" #: piper/window.py:74 piper/window.py:128 msgid "Please make sure your device is supported and plugged in" msgstr "Proszę się upewnić, że urządzenie jest obsługiwane i podłączone" #: piper/window.py:86 msgid "There are unapplied changes. Are you sure you want to quit?" msgstr "Są niezastosowane zmiany. Na pewno zakończyć?" #: piper/window.py:95 msgid "Ooops. ratbagd has disappeared" msgstr "Usługa ratbagd zniknęła" #: piper/window.py:96 msgid "Please restart Piper" msgstr "Proszę ponownie uruchomić program Piper" #. The current device disconnected, which can only happen from the #. mouse perspective as we'd otherwise be in the welcome screen with #. more than one device remaining. Hence, we display the error #. perspective. #: piper/window.py:119 msgid "Your device disconnected!" msgstr "Urządzenie zostało rozłączone." #: piper/window.py:120 msgid "Please make sure your device is plugged in" msgstr "Proszę się upewnić, że urządzenie jest podłączone" #: piper/window.py:159 msgid "Cannot display device SVG" msgstr "Nie można wyświetlić obrazu SVG urządzenia" #: piper/window.py:166 msgid "Newer version of ratbagd required" msgstr "Wymagana jest nowsza wersja usługi ratbagd" #: piper/window.py:167 msgid "Please update to the latest available version" msgstr "Proszę zaktualizować do najnowszej dostępnej wersji" #: piper/window.py:169 msgid "Unknown exception occurred" msgstr "Wystąpił nieznany wyjątek" #: data/ui/AboutDialog.ui.in:10 msgid "Version: @version@" msgstr "Wersja: @version@" #: data/ui/AboutDialog.ui.in:12 msgid "Visit Piper on GitHub" msgstr "Program Piper w serwisie GitHub" #: data/ui/AboutDialog.ui.in:13 msgid "translator-credits" msgstr "" "Piotr Drąg , 2017-2020\n" "Aviary.pl , 2017-2020" #: data/ui/ButtonDialog.ui:65 msgid "Search for a button mapping" msgstr "Wyszukuje mapowanie przycisku" #: data/ui/ButtonDialog.ui:91 msgid "Capture a macro for this button" msgstr "Przechwytuje makro dla tego przycisku" #: data/ui/ButtonDialog.ui:104 msgid "The currently set macro" msgstr "Obecnie ustawione makro" #: data/ui/ButtonDialog.ui:129 msgid "Send keystroke" msgstr "Wyślij kombinację klawiszy" #: data/ui/ButtonDialog.ui:169 msgid "Enter a new key sequence for the macro." msgstr "Proszę wprowadzić nową sekwencję klawiszy dla makra." #: data/ui/ButtonDialog.ui:221 msgid "Press Escape to cancel or Return to accept." msgstr "Klawisz Esc anuluje, a Enter przyjmie." #: data/ui/ButtonDialog.ui:252 msgid "Set the device’s handedness." msgstr "Lewo- lub praworęczność urządzenia." #: data/ui/ButtonDialog.ui:270 msgid "" "This allows you to swap the order of the primary mouse buttons. In left-" "handed mode, the physical left mouse button generates a right mouse click " "and vice versa." msgstr "" "Umożliwia zamianę głównych przycisków myszy. W trybie leworęcznym fizyczny " "lewy przycisk myszy generuje kliknięcie prawym przyciskiem myszy, " "i odwrotnie w trybie praworęcznym." #: data/ui/ButtonDialog.ui:290 msgid "Left Handed" msgstr "Leworęczna" #: data/ui/ButtonDialog.ui:295 msgid "The left mouse button generates a left mouse click" msgstr "Lewy przycisk myszy generuje kliknięcie lewym przyciskiem myszy" #: data/ui/ButtonDialog.ui:309 msgid "Right Handed" msgstr "Praworęczna" #: data/ui/ButtonDialog.ui:314 msgid "The left mouse button generates a right mouse click" msgstr "Lewy przycisk myszy generuje kliknięcie prawym przyciskiem myszy" #: data/ui/ButtonDialog.ui:354 data/ui/LedDialog.ui:414 msgid "Cancel" msgstr "Anuluj" #: data/ui/ButtonDialog.ui:356 data/ui/LedDialog.ui:418 msgid "Ignore any changes made" msgstr "Ignoruje wprowadzone zmiany" #: data/ui/ButtonDialog.ui:362 data/ui/LedDialog.ui:430 #: data/ui/MousePerspective.ui:132 msgid "Apply" msgstr "Zastosuj" #: data/ui/ButtonDialog.ui:365 data/ui/LedDialog.ui:435 msgid "Apply any changes made" msgstr "Zastosowuje wprowadzone zmiany" #: data/ui/ButtonDialog.ui:405 msgid "No button mapping found" msgstr "Nie odnaleziono żadnego mapowania przycisku" #: data/ui/ButtonDialog.ui:421 msgid "Try a different search" msgstr "Proszę spróbować innych słów" #: data/ui/ErrorPerspective.ui:16 msgid "Here, rodent, rodent, rodent…" msgstr "Myszko, myszko, myszko…" #: data/ui/ErrorPerspective.ui:69 msgid "Uh Oh! Something went wrong…" msgstr "Coś się nie powiodło." #: data/ui/ErrorPerspective.ui:73 data/ui/WelcomePerspective.ui:123 msgid "Quit" msgstr "Zakończ" #: data/ui/LedDialog.ui:58 data/ui/LedDialog.ui:209 msgid "Choose a color for the LED" msgstr "Wybiera kolor diody LED" #: data/ui/LedDialog.ui:90 data/ui/LedDialog.ui:257 msgid "Choose a brightness for the LED" msgstr "Wybiera jasność diody LED" #: data/ui/LedDialog.ui:104 data/ui/LedDialog.ui:270 msgid "Brightness" msgstr "Jasność" #: data/ui/LedDialog.ui:135 data/ui/LedDialog.ui:301 msgid "Choose an effect duration for the LED" msgstr "Wybiera czas trwania efektu diody LED" #: data/ui/LedDialog.ui:153 data/ui/LedDialog.ui:319 msgid "ms" msgstr "ms" #: data/ui/LedDialog.ui:175 data/ui/LedDialog.ui:341 msgid "Effect duration" msgstr "Czas trwania efektu" #: data/ui/LedDialog.ui:212 msgid "Pick a Color for the LED" msgstr "Kolor diody LED" #: data/ui/LedDialog.ui:226 msgid "Color" msgstr "Kolor" #: data/ui/LedDialog.ui:380 msgid "This LED is off" msgstr "Ta dioda LED jest wyłączona" #: data/ui/MousePerspective.ui:44 msgid "Something went wrong. The device has been reset to a previous state." msgstr "" "Coś się nie powiodło. Urządzenie zostało przywrócone do poprzedniego stanu." #: data/ui/MousePerspective.ui:101 msgid "Select another profile" msgstr "Wybiera inny profil" #: data/ui/MousePerspective.ui:126 msgid "Commit the changes to the device" msgstr "Zatwierdza zmiany na urządzeniu" #: data/ui/MousePerspective.ui:170 msgid "Click to switch to another profile" msgstr "Przełącza na inny profil" #: data/ui/MousePerspective.ui:185 msgid "Add profile" msgstr "Dodaj profil" #: data/ui/MousePerspective.ui:189 msgid "Add a new profile to the device" msgstr "Dodaje nowy profil do urządzenia" #: data/ui/OptionButton.ui:9 msgid "Open the configuration dialog" msgstr "Otwiera okno konfiguracji" #: data/ui/ProfileRow.ui:16 msgid "Remove this profile from the device" msgstr "Usuwa ten profil z urządzenia" #. Translators: this is used to indicate the active resolution. #: data/ui/ResolutionRow.ui:37 msgid "Active" msgstr "Aktywna" #: data/ui/ResolutionRow.ui:77 msgid "Set this resolution’s DPI" msgstr "Ustawia DPI tej rozdzielczości" #. Translators: the rate at which the device reports movement. #: data/ui/ResolutionsPage.ui:43 msgid "Report rate" msgstr "Tempo zgłaszania" #: data/ui/ResolutionsPage.ui:60 msgid "Change the profile’s report rate" msgstr "Zmienia tempo zgłaszania profilu" #: data/ui/ResolutionsPage.ui:105 msgid "Hz" msgstr "Hz" #. Translators: the sensitivity of the device's sensor. #: data/ui/ResolutionsPage.ui:125 msgid "Sensitivity" msgstr "Czułość" #: data/ui/ResolutionsPage.ui:174 msgid "Add a new resolution to the profile" msgstr "Dodaje nową rozdzielczość do profilu" #: data/ui/WelcomePerspective.ui:20 msgid "Welcome" msgstr "Witamy" #: data/ui/WelcomePerspective.ui:38 msgctxt "A subtitle under the \"Welcome\" title." msgid "Select a device to configure it" msgstr "Proszę wybrać urządzenie do skonfigurowania" #: data/ui/WelcomePerspective.ui:89 msgctxt "A tooltip over the list of devices." msgid "Select a device to configure it" msgstr "Wybiera urządzenie do skonfigurowania" #: data/ui/WelcomePerspective.ui:119 msgid "Select a Device" msgstr "Wybór urządzenia" #: data/ui/Window.ui:8 msgid "_About Piper" msgstr "_O programie" piper-0.8/po/pt_BR.po000066400000000000000000000354521467456234500145150ustar00rootroot00000000000000# Brazilian Portuguese translation for Piper # Copyright (C) 2017-2019 Piper developers # This file is distributed under the same license as the piper package. # Alexandre Oliveira , 2019. # #, fuzzy msgid "" msgstr "" "Project-Id-Version: piper\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2020-05-19 13:59-0300\n" "PO-Revision-Date: 2019-08-18 21:18-0300\n" "Last-Translator: Alexandre Oliveira \n" "Language-Team: Brazilian Portuguese <>\n" "Language: pt_BR\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: data/org.freedesktop.Piper.desktop.in:3 #: data/org.freedesktop.Piper.appdata.xml.in.in:7 msgid "Piper" msgstr "Piper" #: data/org.freedesktop.Piper.desktop.in:4 #: data/org.freedesktop.Piper.appdata.xml.in.in:8 msgid "Configurable mouse configuration utility" msgstr "Ferramenta de configuração de mouses programáveis" #. Translators: Search terms to find this application. Do NOT translate or localize the semicolons! The list MUST also end with a semicolon! #: data/org.freedesktop.Piper.desktop.in:12 msgid "gaming;configuration;mouse;mice;" msgstr "configuração;mouse;gaming;gamer;" #: data/org.freedesktop.Piper.appdata.xml.in.in:10 msgid "" "Piper is a graphical user interface to configure gaming mice. Configuration " "options include changing the resolution (DPI) of the mouse, adding and " "removing profiles, setting LED colors and changing button behaviors." msgstr "" "Piper é uma interface gráfica para configurar mouses para jogos. As opções " "de configuração incluem alterar a resolução (DPI) do mouse, adicionar e " "remover perfis, alterar as cores dos LEDs e alterar o comportamento dos " "botões." #: data/org.freedesktop.Piper.appdata.xml.in.in:16 msgid "" "Piper requires libratbag’s ratbagd, the daemon to actually communicate with " "the mice. Piper is merely a front end to ratbagd, ratbagd must be installed " "and running when Piper is launched." msgstr "" "O Piper requer o programa ratbagd, um daemon que realiza a comunicação com " "o mouse. O aplicativo é apenas uma interface para o ratbagd, ou seja, o " "daemon precisa estar instalado e executando ao iniciar o Piper." #: data/org.freedesktop.Piper.appdata.xml.in.in:33 msgid "The button configuraton page" msgstr "A página de configuração dos botões" #: data/org.freedesktop.Piper.appdata.xml.in.in:37 msgid "The LED configuraton page" msgstr "A página de configuração do(s) LED(s)" #: data/org.freedesktop.Piper.appdata.xml.in.in:41 msgid "The resolution configuraton page" msgstr "A página de configuração das resoluções" #. Translators: section header for mapping one button's click to another. #: piper/buttondialog.py:141 msgid "Button mapping" msgstr "Mapeamento de botões" #. Translators: section header for assigning special functions to buttons. #: piper/buttondialog.py:150 msgid "Special mapping" msgstr "Mapeamento especial" #. Translators: the {} will be replaced with the button index, e.g. #. "Button 1 click". #: piper/buttondialog.py:222 piper/buttonspage.py:90 msgid "Button {} click" msgstr "Clique com o botão {}" #: piper/buttonspage.py:94 msgid "Macro: {}" msgstr "Macro: {}" #. Translators: the button is turned disabled, e.g. off. #: piper/buttonspage.py:97 msgid "Disabled" msgstr "Desabilitado" #. Translators: the button has an unknown function. #: piper/buttonspage.py:100 piper/ratbagd.py:665 msgid "Unknown" msgstr "Desconhecida" #: piper/buttonspage.py:108 msgid "Configure button {}" msgstr "Configurar botão {}" #: piper/mouseperspective.py:90 data/ui/ResolutionsPage.ui:209 msgid "Resolutions" msgstr "Resoluções" #: piper/mouseperspective.py:92 msgid "Buttons" msgstr "Botões" #: piper/mouseperspective.py:94 msgid "LEDs" msgstr "LEDs" #: piper/ratbagd.py:655 msgid "Left mouse button click" msgstr "Clique com o botão esquerdo" #: piper/ratbagd.py:656 msgid "Right mouse button click" msgstr "Clique com o botão direito" #: piper/ratbagd.py:657 msgid "Middle mouse button click" msgstr "Clique com o botão do meio" #: piper/ratbagd.py:658 msgid "Backward" msgstr "Voltar" #: piper/ratbagd.py:659 msgid "Forward" msgstr "Avançar" #: piper/ratbagd.py:664 msgid "Invalid" msgstr "Inválido" #: piper/ratbagd.py:666 msgid "Doubleclick" msgstr "Clique duplo" #: piper/ratbagd.py:667 msgid "Wheel Left" msgstr "Rolar para a esquerda" #: piper/ratbagd.py:668 msgid "Wheel Right" msgstr "Rolar para a direita" #: piper/ratbagd.py:669 msgid "Wheel Up" msgstr "Rolar para cima" #: piper/ratbagd.py:670 msgid "Wheel Down" msgstr "Rolar para baixo" #: piper/ratbagd.py:671 msgid "Ratchet Mode" msgstr "Modo catraca (clique-a-clique)" #: piper/ratbagd.py:672 msgid "Cycle Resolution Up" msgstr "Alternar resolução (para cima)" #: piper/ratbagd.py:673 msgid "Cycle Resolution Down" msgstr "Alternar resolução (para baixo)" #: piper/ratbagd.py:674 msgid "Resolution Up" msgstr "Próxima resolução" #: piper/ratbagd.py:675 msgid "Resolution Down" msgstr "Resolução anterior" #: piper/ratbagd.py:676 msgid "Resolution Switch" msgstr "Trocar resolução" #: piper/ratbagd.py:677 msgid "Default Resolution" msgstr "Resolução padrão" #: piper/ratbagd.py:678 msgid "Cycle Profile Up" msgstr "Alternar perfil (para cima)" #: piper/ratbagd.py:679 msgid "Cycle Profile Down" msgstr "Alternar perfil (para baixo)" #: piper/ratbagd.py:680 msgid "Profile Up" msgstr "Próximo perfil" #: piper/ratbagd.py:681 msgid "Profile Down" msgstr "Perfil anterior" #: piper/ratbagd.py:682 msgid "Second Mode" msgstr "Modo alternativo" #: piper/ratbagd.py:683 msgid "Battery Level" msgstr "Nível da bateria" #. Translators: this is used when there is no macro to preview. #: piper/ratbagd.py:813 data/ui/ButtonDialog.ui:106 data/ui/ButtonDialog.ui:187 msgid "None" msgstr "Nenhum" #. Translators: the LED is off. #: piper/ratbagd.py:895 data/ui/LedDialog.ui:395 msgid "Off" msgstr "Desligado" #. Translators: the LED has a single, solid color. #: piper/ratbagd.py:897 data/ui/LedDialog.ui:66 msgid "Solid" msgstr "Sólido" #. Translators: the LED is cycling between red, green and blue. #: piper/ratbagd.py:899 data/ui/LedDialog.ui:189 msgid "Cycle" msgstr "Alternar" #. Translators: the LED's is pulsating a single color on different #. brightnesses. #: piper/ratbagd.py:902 data/ui/LedDialog.ui:355 msgid "Breathing" msgstr "Pulsar" #: piper/window.py:54 msgid "Cannot connect to ratbagd" msgstr "Não foi possível conectar-se ao ratbagd" #: piper/window.py:55 #, fuzzy msgid "" "Please make sure ratbagd is running and your user is in the required group" msgstr "" "Certifique-se de que o ratbagd está executando e que seu usuário " "possui as permissões necessárias para executá-lo" #: piper/window.py:58 msgid "Incompatible ratbagd API version (required: {}, provided: {})" msgstr "Versão de API do ratbagd incompatível (requer: {}, atual: {})" #: piper/window.py:59 msgid "Please update both piper and libratbag to the latest versions" msgstr "Atualize o piper e o libratbag para a versão mais recente" #: piper/window.py:73 piper/window.py:127 msgid "Cannot find any devices" msgstr "Não foi possível encontrar quaisquer dispositivos" #: piper/window.py:74 piper/window.py:128 msgid "Please make sure your device is supported and plugged in" msgstr "" "Certifique-se de que o seu dispositivo é compatível e está " "conectado" #: piper/window.py:86 msgid "There are unapplied changes. Are you sure you want to quit?" msgstr "Há alterações não salvas. Você tem certeza de que deseja sair?" #: piper/window.py:95 msgid "Ooops. ratbagd has disappeared" msgstr "Oops. O ratbagd desapareceu" #: piper/window.py:96 msgid "Please restart Piper" msgstr "Reinicie o aplicativo" #. The current device disconnected, which can only happen from the #. mouse perspective as we'd otherwise be in the welcome screen with #. more than one device remaining. Hence, we display the error #. perspective. #: piper/window.py:119 msgid "Your device disconnected!" msgstr "O seu dispositivo foi desconectado!" #: piper/window.py:120 msgid "Please make sure your device is plugged in" msgstr "Certifique-se de que seu dispositivo está conectado" #: piper/window.py:159 msgid "Cannot display device SVG" msgstr "Não foi possível exibir a imagem do dispositivo" #: piper/window.py:166 msgid "Newer version of ratbagd required" msgstr "Requer uma versão mais recente do ratbagd" #: piper/window.py:167 msgid "Please update to the latest available version" msgstr "Atualize para a versão mais recente" #: piper/window.py:169 msgid "Unknown exception occurred" msgstr "Ocorreu uma exceção desconhecida" #: data/ui/AboutDialog.ui.in:10 msgid "Version: @version@" msgstr "Versão: @version@" #: data/ui/AboutDialog.ui.in:12 #, fuzzy msgid "Visit Piper on GitHub" msgstr "Visite o repositório no GitHub" #: data/ui/AboutDialog.ui.in:13 msgid "translator-credits" msgstr "Alexandre Oliveira , 2019" #: data/ui/ButtonDialog.ui:65 msgid "Search for a button mapping" msgstr "Pesquisar por mapeamento de botão" #: data/ui/ButtonDialog.ui:91 msgid "Capture a macro for this button" msgstr "Capturar macro para o botão" #: data/ui/ButtonDialog.ui:104 msgid "The currently set macro" msgstr "O macro atualmente definido" #: data/ui/ButtonDialog.ui:129 msgid "Send keystroke" msgstr "Enviar sequência de teclas" #: data/ui/ButtonDialog.ui:169 msgid "Enter a new key sequence for the macro." msgstr "Insira uma nova sequência de teclas para o macro." #: data/ui/ButtonDialog.ui:221 msgid "Press Escape to cancel or Return to accept." msgstr "Aperte Esc para cancelar ou Enter para aceitar." #: data/ui/ButtonDialog.ui:252 msgid "Set the device’s handedness." msgstr "Selecionar a mão que usa o mouse" #: data/ui/ButtonDialog.ui:270 msgid "" "This allows you to swap the order of the primary mouse buttons. In left-" "handed mode, the physical left mouse button generates a right mouse click " "and vice versa." msgstr "" "Isto permite que você troque a ordem dos botões primários do mouse. No modo " "canhoto, o botão esquerdo físico do mouse gera um clique com o botão direito " "e vice-versa." #: data/ui/ButtonDialog.ui:290 msgid "Left Handed" msgstr "Canhoto" #: data/ui/ButtonDialog.ui:295 msgid "The left mouse button generates a left mouse click" msgstr "O botão esquerdo do mouse gera um clique com o botão direito" #: data/ui/ButtonDialog.ui:309 msgid "Right Handed" msgstr "Destro" #: data/ui/ButtonDialog.ui:314 msgid "The left mouse button generates a right mouse click" msgstr "O botão esquerdo do mouse gera um clique com o botão esquerdo" #: data/ui/ButtonDialog.ui:354 data/ui/LedDialog.ui:414 msgid "Cancel" msgstr "Cancelar" #: data/ui/ButtonDialog.ui:356 data/ui/LedDialog.ui:418 msgid "Ignore any changes made" msgstr "Ignorar alterações" #: data/ui/ButtonDialog.ui:362 data/ui/LedDialog.ui:430 #: data/ui/MousePerspective.ui:132 msgid "Apply" msgstr "Aplicar" #: data/ui/ButtonDialog.ui:365 data/ui/LedDialog.ui:435 msgid "Apply any changes made" msgstr "Aplicar alterações" #: data/ui/ButtonDialog.ui:405 msgid "No button mapping found" msgstr "Nenhum mapeamento de botão encontrado" #: data/ui/ButtonDialog.ui:421 msgid "Try a different search" msgstr "Tente uma nova pesquisa" #: data/ui/ErrorPerspective.ui:16 msgid "Here, rodent, rodent, rodent…" msgstr "Aqui, ratinho, ratinho, ratinho..." #: data/ui/ErrorPerspective.ui:69 msgid "Uh Oh! Something went wrong…" msgstr "Uh oh! Algo de errado, não está certo..." #: data/ui/ErrorPerspective.ui:73 data/ui/WelcomePerspective.ui:123 msgid "Quit" msgstr "Sair" #: data/ui/LedDialog.ui:58 data/ui/LedDialog.ui:209 msgid "Choose a color for the LED" msgstr "Escolha a cor do LED" #: data/ui/LedDialog.ui:90 data/ui/LedDialog.ui:257 msgid "Choose a brightness for the LED" msgstr "Escolha a intensidade do LED" #: data/ui/LedDialog.ui:104 data/ui/LedDialog.ui:270 msgid "Brightness" msgstr "Brilho" #: data/ui/LedDialog.ui:135 data/ui/LedDialog.ui:301 msgid "Choose an effect duration for the LED" msgstr "Escolha a duração do efeito do LED" #: data/ui/LedDialog.ui:153 data/ui/LedDialog.ui:319 msgid "ms" msgstr "ms" #: data/ui/LedDialog.ui:175 data/ui/LedDialog.ui:341 msgid "Effect duration" msgstr "Duração do efeito" #: data/ui/LedDialog.ui:212 msgid "Pick a Color for the LED" msgstr "Escolha a cor do LED" #: data/ui/LedDialog.ui:226 msgid "Color" msgstr "Cor" #: data/ui/LedDialog.ui:380 msgid "This LED is off" msgstr "Este LED está desligado" #: data/ui/MousePerspective.ui:44 msgid "Something went wrong. The device has been reset to a previous state." msgstr "" "Aconteceu algo inesperado. O dispositivo foi restaurado para o estado " "anterior." #: data/ui/MousePerspective.ui:101 msgid "Select another profile" msgstr "Escolher outro perfil" #: data/ui/MousePerspective.ui:126 msgid "Commit the changes to the device" msgstr "Salvar alterações no dispositivo" #: data/ui/MousePerspective.ui:170 msgid "Click to switch to another profile" msgstr "Clique para trocar para outro perfil" #: data/ui/MousePerspective.ui:185 msgid "Add profile" msgstr "Adicionar perfil" #: data/ui/MousePerspective.ui:189 msgid "Add a new profile to the device" msgstr "Adicionar um novo perfil ao dispositivo" #: data/ui/OptionButton.ui:9 msgid "Open the configuration dialog" msgstr "Abrir a janela de configurações" #: data/ui/ProfileRow.ui:16 msgid "Remove this profile from the device" msgstr "Remover este perfil do dispositivo" #. Translators: this is used to indicate the active resolution. #: data/ui/ResolutionRow.ui:37 msgid "Active" msgstr "Ativo" #: data/ui/ResolutionRow.ui:77 msgid "Set this resolution’s DPI" msgstr "Definir a resolução em DPI" #. Translators: the rate at which the device reports movement. #: data/ui/ResolutionsPage.ui:43 msgid "Report rate" msgstr "Frequência de atualização" #: data/ui/ResolutionsPage.ui:60 msgid "Change the profile’s report rate" msgstr "Alterar a frequência de atualização do perfil" #: data/ui/ResolutionsPage.ui:105 msgid "Hz" msgstr "Hz" #. Translators: the sensitivity of the device's sensor. #: data/ui/ResolutionsPage.ui:125 msgid "Sensitivity" msgstr "Sensibilidade" #: data/ui/ResolutionsPage.ui:174 msgid "Add a new resolution to the profile" msgstr "Adicionar uma nova resolução ao perfil" #: data/ui/WelcomePerspective.ui:20 msgid "Welcome" msgstr "Bem-vindo(a)" #: data/ui/WelcomePerspective.ui:38 msgctxt "A subtitle under the \"Welcome\" title." msgid "Select a device to configure it" msgstr "Selecione um dispositivo para configurá-lo" #: data/ui/WelcomePerspective.ui:89 msgctxt "A tooltip over the list of devices." msgid "Select a device to configure it" msgstr "Selecione um dispositivo para configurá-lo" #: data/ui/WelcomePerspective.ui:119 msgid "Select a Device" msgstr "Selecione um dispositivo" #: data/ui/Window.ui:8 msgid "_About Piper" msgstr "Sobre o aplicativo" #~ msgid "org.freedesktop.Piper" #~ msgstr "org.freedesktop.Piper" piper-0.8/po/ru.po000066400000000000000000000414451467456234500141340ustar00rootroot00000000000000# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the piper package. # FIRST AUTHOR , YEAR. # #, fuzzy msgid "" msgstr "" "Project-Id-Version: piper\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2020-11-30 18:32+0700\n" "PO-Revision-Date: 2020-11-30 19:34+0700\n" "Last-Translator: Vail Rahmatulin \n" "Language-Team:\n" "Language: RU\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: data/org.freedesktop.Piper.desktop.in:3 #: data/org.freedesktop.Piper.appdata.xml.in.in:7 msgid "Piper" msgstr "Piper" #: data/org.freedesktop.Piper.desktop.in:4 #: data/org.freedesktop.Piper.appdata.xml.in.in:8 msgid "Configurable mouse configuration utility" msgstr "Утилита для настройки мыши" #. Translators: Do NOT translate or transliterate this text (this is an icon file name)! #: data/org.freedesktop.Piper.desktop.in:7 msgid "org.freedesktop.Piper" msgstr "org.freedesktop.Piper" #. Translators: Search terms to find this application. Do NOT translate or localize the semicolons! The list MUST also end with a semicolon! #: data/org.freedesktop.Piper.desktop.in:12 msgid "gaming;configuration;mouse;mice;" msgstr "игра;конфигурация;мышь;мыши;" #: data/org.freedesktop.Piper.appdata.xml.in.in:10 msgid "" "Piper is a graphical user interface to configure gaming mice. Configuration " "options include changing the resolution (DPI) of the mouse, adding and " "removing profiles, setting LED colors and changing button behaviors." msgstr "" "Piper - это графический интерфейс пользователя для настройки игровых мышей." "Варианты конфигурации включают изменение разрешающей способности (DPI) мыши, " "добавление и удаление профилей, настройки цвета светодиода и изменение поведения " "кнопки." #: data/org.freedesktop.Piper.appdata.xml.in.in:16 msgid "" "Piper requires libratbag’s ratbagd, the daemon to actually communicate with " "the mice. Piper is merely a front end to ratbagd, ratbagd must be installed " "and running when Piper is launched." msgstr "" "Piper требует библиотеку libratbagd от сервиса ratbagd, чтобы общаться с " "мышью. Piper-это просто графический интерфейс, ratbagd должен быть " "установлен и запущен перед запуском Piper." #: data/org.freedesktop.Piper.appdata.xml.in.in:27 msgid "The button configuraton page" msgstr "Страница настройки кнопок" #: data/org.freedesktop.Piper.appdata.xml.in.in:31 msgid "The LED configuraton page" msgstr "Страница настройки LED" #: data/org.freedesktop.Piper.appdata.xml.in.in:35 msgid "The resolution configuraton page" msgstr "Страница настройки разрешения (DPI)" #. Translators: section header for mapping one button's click to another. #: piper/buttondialog.py:127 msgid "Button mapping" msgstr "Привязка кнопок" #. Translators: section header for assigning special functions to buttons. #: piper/buttondialog.py:136 msgid "Special mapping" msgstr "Отдельная привязка" #. Translators: the {} will be replaced with the button index, e.g. #. "Button 1 click". #: piper/buttondialog.py:208 piper/buttonspage.py:76 msgid "Button {} click" msgstr "Клик кнопки {}" #: piper/buttonspage.py:80 msgid "Macro: {}" msgstr "Макро: {}" #. Translators: the button is turned disabled, e.g. off. #: piper/buttonspage.py:83 msgid "Disabled" msgstr "Выключено" #. Translators: the button has an unknown function. #: piper/buttonspage.py:86 piper/ratbagd.py:665 msgid "Unknown" msgstr "Неизвестный" #: piper/buttonspage.py:94 msgid "Configure button {}" msgstr "Настройки кнопки {}" #: piper/mouseperspective.py:76 data/ui/ResolutionsPage.ui:209 msgid "Resolutions" msgstr "Разрешение" #: piper/mouseperspective.py:78 msgid "Buttons" msgstr "Кнопки" #: piper/mouseperspective.py:80 msgid "LEDs" msgstr "LEDs" #: piper/ratbagd.py:655 msgid "Left mouse button click" msgstr "Клик левой кнопки мыши" #: piper/ratbagd.py:656 msgid "Right mouse button click" msgstr "Клик правой кнопки мыши" #: piper/ratbagd.py:657 msgid "Middle mouse button click" msgstr "Клик средней кнопки мыши" #: piper/ratbagd.py:658 msgid "Backward" msgstr "Назад" #: piper/ratbagd.py:659 msgid "Forward" msgstr "Вперёд" #: piper/ratbagd.py:664 msgid "Invalid" msgstr "Недействительный" #: piper/ratbagd.py:666 msgid "Doubleclick" msgstr "Двойной клик" #: piper/ratbagd.py:667 msgid "Wheel Left" msgstr "Колесо влево" #: piper/ratbagd.py:668 msgid "Wheel Right" msgstr "Колесо вправо" #: piper/ratbagd.py:669 msgid "Wheel Up" msgstr "Колесо вверх" #: piper/ratbagd.py:670 msgid "Wheel Down" msgstr "Колесо вниз" #: piper/ratbagd.py:671 msgid "Ratchet Mode" msgstr "Режим храповика" #: piper/ratbagd.py:672 msgid "Cycle Resolution Up" msgstr "Циклически увеличить разрешение" #: piper/ratbagd.py:673 msgid "Cycle Resolution Down" msgstr "Циклически уменьшить разрешение" #: piper/ratbagd.py:674 msgid "Resolution Up" msgstr "Увеличить разрешение" #: piper/ratbagd.py:675 msgid "Resolution Down" msgstr "Уменьшить разрешение" #: piper/ratbagd.py:676 msgid "Resolution Switch" msgstr "Изменить разрешение" #: piper/ratbagd.py:677 msgid "Default Resolution" msgstr "Разрешение по умолчанию" #: piper/ratbagd.py:678 msgid "Cycle Profile Up" msgstr "Следующий профиль (циклически)" #: piper/ratbagd.py:679 msgid "Cycle Profile Down" msgstr "Предыдущий профиль (циклически)" #: piper/ratbagd.py:680 msgid "Profile Up" msgstr "Следующий профиль" #: piper/ratbagd.py:681 msgid "Profile Down" msgstr "Предыдущий профиль" #: piper/ratbagd.py:682 msgid "Second Mode" msgstr "Другой режим" #: piper/ratbagd.py:683 msgid "Battery Level" msgstr "Уровень батареи" #. Translators: this is used when there is no macro to preview. #: piper/ratbagd.py:813 data/ui/ButtonDialog.ui:106 data/ui/ButtonDialog.ui:187 msgid "None" msgstr "Ничего" #. Translators: the LED is off. #: piper/ratbagd.py:895 data/ui/LedDialog.ui:395 msgid "Off" msgstr "Выключить" #. Translators: the LED has a single, solid color. #: piper/ratbagd.py:897 data/ui/LedDialog.ui:66 msgid "Solid" msgstr "Один цвет" #. Translators: the LED is cycling between red, green and blue. #: piper/ratbagd.py:899 data/ui/LedDialog.ui:189 msgid "Cycle" msgstr "Цикл" #. Translators: the LED's is pulsating a single color on different #. brightnesses. #: piper/ratbagd.py:902 data/ui/LedDialog.ui:355 msgid "Breathing" msgstr "Пульсация" #: piper/window.py:40 msgid "Cannot connect to ratbagd" msgstr "Невозможно подключиться к ratbagd" #: piper/window.py:41 msgid "" "Please make sure ratbagd is running and your user is in the required group" msgstr "" "Пожалуйста, убедитесь, что ratbag работает и ваш пользователь находится в нужной группе" #: piper/window.py:44 msgid "Incompatible ratbagd API version (required: {}, provided: {})" msgstr "Несовместимая версия API ratbags (требуется: {}, предоставляется: {})" #: piper/window.py:45 msgid "Please update both piper and libratbag to the latest versions" msgstr "Пожалуйста обновите piper и libratbag до последних версий" #: piper/window.py:59 piper/window.py:113 msgid "Cannot find any devices" msgstr "Не удается найти никаких устройств" #: piper/window.py:60 piper/window.py:114 msgid "Please make sure your device is supported and plugged in" msgstr "Пожалуйста, убедитесь, что ваше устройство поддерживается и подключено" #: piper/window.py:72 msgid "There are unapplied changes. Are you sure you want to quit?" msgstr "Есть непримененные изменения. Все равно выйти?" #: piper/window.py:81 msgid "Ooops. ratbagd has disappeared" msgstr "Ой! ratbagd пропал!" #: piper/window.py:82 msgid "Please restart Piper" msgstr "Пожалуйста, перезапустите Piper" #. The current device disconnected, which can only happen from the #. mouse perspective as we'd otherwise be in the welcome screen with #. more than one device remaining. Hence, we display the error #. perspective. #: piper/window.py:105 msgid "Your device disconnected!" msgstr "Ваше устройство отключено!" #: piper/window.py:106 msgid "Please make sure your device is plugged in" msgstr "Убедитесь, что ваше устройство подключено" #: piper/window.py:145 msgid "Cannot display device SVG" msgstr "Невозможно показать изображение устройства" #: piper/window.py:152 msgid "Newer version of ratbagd required" msgstr "Необходима более новая версия ratbagd" #: piper/window.py:153 msgid "Please update to the latest available version" msgstr "Пожалуйста обновитесь до последней версии" #: piper/window.py:155 msgid "Unknown exception occurred" msgstr "Произошла неизвестная ошибка" #: data/ui/AboutDialog.ui.in:10 msgid "Version: @version@" msgstr "Версия: @version@" #: data/ui/AboutDialog.ui.in:12 msgid "Visit Piper on GitHub" msgstr "Перейти на страницу Piper" #: data/ui/AboutDialog.ui.in:13 msgid "translator-credits" msgstr "Ваиль Рахматулин " #: data/ui/ButtonDialog.ui:65 msgid "Search for a button mapping" msgstr "Поиск привязок кнопок" #: data/ui/ButtonDialog.ui:91 msgid "Capture a macro for this button" msgstr "Зписать макрос для этой кнопки" #: data/ui/ButtonDialog.ui:104 msgid "The currently set macro" msgstr "Установлен текущий макрос" #: data/ui/ButtonDialog.ui:129 msgid "Send keystroke" msgstr "Отправить комбинацию клавиш" #: data/ui/ButtonDialog.ui:169 msgid "Enter a new key sequence for the macro." msgstr "Введите новую последовательность клавиш для макроса." #: data/ui/ButtonDialog.ui:235 msgid "Set the device’s handedness." msgstr "Левая/правая рука." #: data/ui/ButtonDialog.ui:253 msgid "" "This allows you to swap the order of the primary mouse buttons. In left-" "handed mode, the physical left mouse button generates a right mouse click " "and vice versa." msgstr "" "Это позволяет изменить порядок основных кнопок мыши. В режиме левой руки " "физическая левая кнопка мыши работает как правая и наоборот." #: data/ui/ButtonDialog.ui:273 msgid "Left Handed" msgstr "Левая рука" #: data/ui/ButtonDialog.ui:278 msgid "The left mouse button generates a left mouse click" msgstr "Левая кнопка мыши генерирует левый клик" #: data/ui/ButtonDialog.ui:292 msgid "Right Handed" msgstr "Правая рука" #: data/ui/ButtonDialog.ui:297 msgid "The left mouse button generates a right mouse click" msgstr "Левая кнопка мыши генерирует правый клик" #: data/ui/ButtonDialog.ui:337 data/ui/LedDialog.ui:414 msgid "Cancel" msgstr "Отмена" #: data/ui/ButtonDialog.ui:339 data/ui/LedDialog.ui:418 msgid "Ignore any changes made" msgstr "Игнорировать все сделанные изменения" #: data/ui/ButtonDialog.ui:345 data/ui/LedDialog.ui:430 #: data/ui/MousePerspective.ui:132 msgid "Apply" msgstr "Применить" #: data/ui/ButtonDialog.ui:348 data/ui/LedDialog.ui:435 msgid "Apply any changes made" msgstr "Применить все сделанные изменения" #: data/ui/ButtonDialog.ui:388 msgid "No button mapping found" msgstr "Не найдено никаких привязок" #: data/ui/ButtonDialog.ui:404 msgid "Try a different search" msgstr "Попробуйте сформулировать иначе" #: data/ui/ErrorPerspective.ui:16 msgid "Here, rodent, rodent, rodent…" msgstr "Тут мыш, мыш, мыш…" #: data/ui/ErrorPerspective.ui:69 msgid "Uh Oh! Something went wrong…" msgstr "Ах! Что-то пошло не так…" #: data/ui/ErrorPerspective.ui:73 data/ui/WelcomePerspective.ui:123 msgid "Quit" msgstr "Выйти" #: data/ui/LedDialog.ui:58 data/ui/LedDialog.ui:209 msgid "Choose a color for the LED" msgstr "Выберите цвет подсветки" #: data/ui/LedDialog.ui:90 data/ui/LedDialog.ui:257 msgid "Choose a brightness for the LED" msgstr "Выберите яркость подсветки" #: data/ui/LedDialog.ui:104 data/ui/LedDialog.ui:270 msgid "Brightness" msgstr "Яркость" #: data/ui/LedDialog.ui:135 data/ui/LedDialog.ui:301 msgid "Choose an effect duration for the LED" msgstr "Выберите эффект подсветки" #: data/ui/LedDialog.ui:153 data/ui/LedDialog.ui:319 msgid "ms" msgstr "мс" #: data/ui/LedDialog.ui:175 data/ui/LedDialog.ui:341 msgid "Effect duration" msgstr "Продолжительность эффекта" #: data/ui/LedDialog.ui:212 msgid "Pick a Color for the LED" msgstr "Определите цвет для подсветки" #: data/ui/LedDialog.ui:226 msgid "Color" msgstr "Цвет" #: data/ui/LedDialog.ui:380 msgid "This LED is off" msgstr "Подсветка отключена" #: data/ui/MousePerspective.ui:44 msgid "Something went wrong. The device has been reset to a previous state." msgstr "Что-то пошло не так. Устройство было восстановлено в предыдущее состояние." #: data/ui/MousePerspective.ui:101 msgid "Select another profile" msgstr "Выберите другой профиль" #: data/ui/MousePerspective.ui:126 msgid "Commit the changes to the device" msgstr "Отправить изменения в устройство" #: data/ui/MousePerspective.ui:170 msgid "Click to switch to another profile" msgstr "Кликните чтобы выбрать другой профиль" #: data/ui/MousePerspective.ui:185 msgid "Add profile" msgstr "Добавить профиль" #: data/ui/MousePerspective.ui:189 msgid "Add a new profile to the device" msgstr "Добавить новый профиль устройства" #: data/ui/OptionButton.ui:9 msgid "Open the configuration dialog" msgstr "Открыть диалог настроек" #: data/ui/ProfileRow.ui:16 msgid "Remove this profile from the device" msgstr "Удалить этот профиль устройства" #. Translators: this is used to indicate the active resolution. #: data/ui/ResolutionRow.ui:37 msgid "Active" msgstr "Активный" #: data/ui/ResolutionRow.ui:77 msgid "Set this resolution’s DPI" msgstr "Определить разрешение DPI" #. Translators: the rate at which the device reports movement. #: data/ui/ResolutionsPage.ui:43 msgid "Report rate" msgstr "Скорость отклика" #: data/ui/ResolutionsPage.ui:60 msgid "Change the profile’s report rate" msgstr "Изменить профиль скорости отклика" #: data/ui/ResolutionsPage.ui:105 msgid "Hz" msgstr "Гц" #. Translators: the sensitivity of the device's sensor. #: data/ui/ResolutionsPage.ui:125 msgid "Sensitivity" msgstr "Чувствительность" #: data/ui/ResolutionsPage.ui:174 msgid "Add a new resolution to the profile" msgstr "Добавить новое разрешение к профилю" #: data/ui/WelcomePerspective.ui:20 msgid "Welcome" msgstr "Добро пожаловать" #: data/ui/WelcomePerspective.ui:38 msgctxt "A subtitle under the \"Welcome\" title." msgid "Select a device to configure it" msgstr "Выберите устройство для настройки" #: data/ui/WelcomePerspective.ui:89 msgctxt "A tooltip over the list of devices." msgid "Select a device to configure it" msgstr "Выберите устройство для настройки" #: data/ui/WelcomePerspective.ui:119 msgid "Select a Device" msgstr "Выбрать устройство" #: data/ui/Window.ui:8 msgid "_About Piper" msgstr "_Про Piper" piper-0.8/po/sv.po000066400000000000000000000354101467456234500141310ustar00rootroot00000000000000# Swedish localization of Piper # Copyright (C) 2017 the piper developers # This file is distributed under the same license as the piper package. # Patrik Nilsson , 2017. # Stephan Lachnit , 2020. # msgid "" msgstr "" "Project-Id-Version: piper\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2020-05-19 12:08+0200\n" "PO-Revision-Date: 2020-05-19 12:17+0200\n" "Last-Translator: Stephan Lachnit \n" "Language-Team: Swedish <>\n" "Language: sv\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Generator: Gtranslator 3.36.0\n" "Plural-Forms: nplurals=2; plural=(n != 1)\n" #: data/org.freedesktop.Piper.desktop.in:3 msgid "Piper" msgstr "Piper" #: data/org.freedesktop.Piper.desktop.in:4 #: data/org.freedesktop.Piper.appdata.xml.in.in:8 msgid "Configurable mouse configuration utility" msgstr "Konfigurationsprogram för programmerbara möss" #. Translators: Do NOT translate or transliterate this text (this is an icon file name)! #: data/org.freedesktop.Piper.desktop.in:7 msgid "org.freedesktop.Piper" msgstr "org.freedesktop.Piper" #. Translators: Search terms to find this application. Do NOT translate or localize the semicolons! The list MUST also end with a semicolon! #: data/org.freedesktop.Piper.desktop.in:12 msgid "gaming;configuration;mouse;mice;" msgstr "gaming;spel;konfiguration;mus;möss;" #: data/org.freedesktop.Piper.appdata.xml.in.in:10 msgid "" "Piper is a graphical user interface to configure gaming mice. Configuration " "options include changing the resolution (DPI) of the mouse, adding and " "removing profiles, setting LED colors and changing button behaviors." msgstr "" "Piper är ett användargränssnitt för att konfigurera möss. Det finns optioner " "för att ändra musens upplösning (DPI), lägga till och ta bort profiler, " "ställa in LED färger och ändra knappbindningar." #: data/org.freedesktop.Piper.appdata.xml.in.in:16 msgid "" "Piper requires libratbag’s ratbagd, the daemon to actually communicate with " "the mice. Piper is merely a front end to ratbagd, ratbagd must be installed " "and running when Piper is launched." msgstr "" "Piper behöver libratbags ratbagd, demonen som kommunicerar faktiskt med " "musen.Piper är bara ett användargränssnitt för ratbagd, ratbagd måste vara " "installerad och körs." #: data/org.freedesktop.Piper.appdata.xml.in.in:27 msgid "The button configuraton page" msgstr "Öppna konfigurationsdialogen för knappar" #: data/org.freedesktop.Piper.appdata.xml.in.in:31 msgid "The LED configuraton page" msgstr "Öppna konfigurationsdialogen för lysdioder" #: data/org.freedesktop.Piper.appdata.xml.in.in:35 msgid "The resolution configuraton page" msgstr "Öppna konfigurationsdialogen för upplösningar" #. Translators: section header for mapping one button's click to another. #: piper/buttondialog.py:141 msgid "Button mapping" msgstr "Knappbindning" #. Translators: section header for assigning special functions to buttons. #: piper/buttondialog.py:150 msgid "Special mapping" msgstr "Speciell bindning" #. Translators: the {} will be replaced with the button index, e.g. #. "Button 1 click". #: piper/buttondialog.py:222 piper/buttonspage.py:90 msgid "Button {} click" msgstr "Knapp {} klick" #: piper/buttonspage.py:94 msgid "Macro: {}" msgstr "Makro: {}" #. Translators: the button is turned disabled, e.g. off. #: piper/buttonspage.py:97 msgid "Disabled" msgstr "Inaktiverad" #. Translators: the button has an unknown function. #: piper/buttonspage.py:100 piper/ratbagd.py:665 msgid "Unknown" msgstr "Okänd" #: piper/buttonspage.py:108 msgid "Configure button {}" msgstr "Konfigurera knapp {}" #: piper/mouseperspective.py:90 data/ui/ResolutionsPage.ui:209 msgid "Resolutions" msgstr "Upplösningar" #: piper/mouseperspective.py:92 msgid "Buttons" msgstr "Knappar" #: piper/mouseperspective.py:94 msgid "LEDs" msgstr "Lysdioder" #: piper/ratbagd.py:655 msgid "Left mouse button click" msgstr "Vänster musklick" #: piper/ratbagd.py:656 msgid "Right mouse button click" msgstr "Höger musklick" #: piper/ratbagd.py:657 msgid "Middle mouse button click" msgstr "Mellersta musklick" #: piper/ratbagd.py:658 msgid "Backward" msgstr "Bakåt" #: piper/ratbagd.py:659 msgid "Forward" msgstr "Framåt" #: piper/ratbagd.py:664 msgid "Invalid" msgstr "Ogiltig" #: piper/ratbagd.py:666 msgid "Doubleclick" msgstr "Dubbelklick" #: piper/ratbagd.py:667 msgid "Wheel Left" msgstr "Mushjul vänster" #: piper/ratbagd.py:668 msgid "Wheel Right" msgstr "Mushjul höger" #: piper/ratbagd.py:669 msgid "Wheel Up" msgstr "Mushjul Upp" #: piper/ratbagd.py:670 msgid "Wheel Down" msgstr "Mushjul Ner" #: piper/ratbagd.py:671 msgid "Ratchet Mode" msgstr "Spärrläge" #: piper/ratbagd.py:672 msgid "Cycle Resolution Up" msgstr "Cykla upplösning upp" #: piper/ratbagd.py:673 msgid "Cycle Resolution Down" msgstr "Cykla upplösning ner" #: piper/ratbagd.py:674 msgid "Resolution Up" msgstr "Upplösning upp" #: piper/ratbagd.py:675 msgid "Resolution Down" msgstr "Upplösning ner" #: piper/ratbagd.py:676 msgid "Resolution Switch" msgstr "Växla upplösning" #: piper/ratbagd.py:677 msgid "Default Resolution" msgstr "Standardupplösning" #: piper/ratbagd.py:678 msgid "Cycle Profile Up" msgstr "Cykla profil upp" #: piper/ratbagd.py:679 msgid "Cycle Profile Down" msgstr "Cykla profil ner" #: piper/ratbagd.py:680 msgid "Profile Up" msgstr "Profil upp" #: piper/ratbagd.py:681 msgid "Profile Down" msgstr "Profil ner" #: piper/ratbagd.py:682 msgid "Second Mode" msgstr "Andra läget" #: piper/ratbagd.py:683 msgid "Battery Level" msgstr "Batterinivå" #. Translators: this is used when there is no macro to preview. #: piper/ratbagd.py:813 data/ui/ButtonDialog.ui:106 data/ui/ButtonDialog.ui:187 msgid "None" msgstr "Ingen" #. Translators: the LED is off. #: piper/ratbagd.py:895 data/ui/LedDialog.ui:395 msgid "Off" msgstr "Av" #. Translators: the LED has a single, solid color. #: piper/ratbagd.py:897 data/ui/LedDialog.ui:66 msgid "Solid" msgstr "Solid" #. Translators: the LED is cycling between red, green and blue. #: piper/ratbagd.py:899 data/ui/LedDialog.ui:189 msgid "Cycle" msgstr "Cykla" #. Translators: the LED's is pulsating a single color on different #. brightnesses. #: piper/ratbagd.py:902 data/ui/LedDialog.ui:355 msgid "Breathing" msgstr "Pulserande" #: piper/window.py:54 msgid "Cannot connect to ratbagd" msgstr "Kan inte ansluta till ratbagd" #: piper/window.py:55 msgid "" "Please make sure ratbagd is running and your user is in the required group" msgstr "Se till att ratbagd körs och att användaren är i den riktiga gruppen" #: piper/window.py:58 msgid "Incompatible ratbagd API version (required: {}, provided: {})" msgstr "Inkompatibel ratbagd API version (behövs: {}, försedd: {})" #: piper/window.py:59 msgid "Please update both piper and libratbag to the latest versions" msgstr "Uppdatera både Piper och libratbag till den senaste versionen" #: piper/window.py:73 piper/window.py:127 msgid "Cannot find any devices" msgstr "Kan inte hitta några enheter" #: piper/window.py:74 piper/window.py:128 msgid "Please make sure your device is supported and plugged in" msgstr "Se till att din enhet stöds och är ansluten" #: piper/window.py:86 msgid "There are unapplied changes. Are you sure you want to quit?" msgstr "Det finns ej utförda förändringar. Är du säker på att du vill avsluta?" #: piper/window.py:95 msgid "Ooops. ratbagd has disappeared" msgstr "Aj då. ratbagd är försvunnen" #: piper/window.py:96 msgid "Please restart Piper" msgstr "Starta om Piper" #. The current device disconnected, which can only happen from the #. mouse perspective as we'd otherwise be in the welcome screen with #. more than one device remaining. Hence, we display the error #. perspective. #: piper/window.py:119 msgid "Your device disconnected!" msgstr "Anslutningen till din enhet bröts!" #: piper/window.py:120 msgid "Please make sure your device is plugged in" msgstr "Se till att din enhet är ansluten" #: piper/window.py:159 msgid "Cannot display device SVG" msgstr "Kan inte visa enhetens SVG" #: piper/window.py:166 msgid "Newer version of ratbagd required" msgstr "Nyare version av ratbagd behövs" #: piper/window.py:167 msgid "Please update to the latest available version" msgstr "Uppdatera till senaste versionen" #: piper/window.py:169 msgid "Unknown exception occurred" msgstr "Okänt fel av typ \"exception\" inträffade" #: data/ui/AboutDialog.ui.in:10 msgid "Version: @version@" msgstr "Version: @version@" #: data/ui/AboutDialog.ui.in:12 msgid "Visit Piper on GitHub" msgstr "Besök Piper på GitHub" #: data/ui/AboutDialog.ui.in:13 msgid "translator-credits" msgstr "Patrik Nilsson och Stephan Lachnit" #: data/ui/ButtonDialog.ui:65 msgid "Search for a button mapping" msgstr "Sök efter en knappbindning" #: data/ui/ButtonDialog.ui:91 msgid "Capture a macro for this button" msgstr "Spela in makro för den här knappen" #: data/ui/ButtonDialog.ui:104 msgid "The currently set macro" msgstr "Det nuvarande inställda makrot" #: data/ui/ButtonDialog.ui:129 msgid "Send keystroke" msgstr "Skicka knapptryckning" #: data/ui/ButtonDialog.ui:169 msgid "Enter a new key sequence for the macro." msgstr "Ange en ny nyckelsekvens för makrot." #: data/ui/ButtonDialog.ui:221 msgid "Press Escape to cancel or Return to accept." msgstr "Tryck på Escape för att avbryta eller Retur för att acceptera." #: data/ui/ButtonDialog.ui:252 msgid "Set the device’s handedness." msgstr "Ställ in enheten för vänster eller höger-hänthet." #: data/ui/ButtonDialog.ui:270 msgid "" "This allows you to swap the order of the primary mouse buttons. In left-" "handed mode, the physical left mouse button generates a right mouse click " "and vice versa." msgstr "" "Detta låter dig skifta ordningen på de primära musknapparna. I vänsterhänt " "läge genererar den vänstra musknappen ett högerklick och vice versa." #: data/ui/ButtonDialog.ui:290 msgid "Left Handed" msgstr "Vänsterhänt" #: data/ui/ButtonDialog.ui:295 msgid "The left mouse button generates a left mouse click" msgstr "Den vänstra musknappen genererar ett vänsterklick" #: data/ui/ButtonDialog.ui:309 msgid "Right Handed" msgstr "Högerhänt" #: data/ui/ButtonDialog.ui:314 msgid "The left mouse button generates a right mouse click" msgstr "Den vänstra musknappen genererar ett högerklick" #: data/ui/ButtonDialog.ui:354 data/ui/LedDialog.ui:414 msgid "Cancel" msgstr "Avbryt" #: data/ui/ButtonDialog.ui:356 data/ui/LedDialog.ui:418 msgid "Ignore any changes made" msgstr "Ignorera eventuella ändringar" #: data/ui/ButtonDialog.ui:362 data/ui/LedDialog.ui:430 #: data/ui/MousePerspective.ui:132 msgid "Apply" msgstr "Tillämpa" #: data/ui/ButtonDialog.ui:365 data/ui/LedDialog.ui:435 msgid "Apply any changes made" msgstr "Tillämpa eventuella ändringar" #: data/ui/ButtonDialog.ui:405 msgid "No button mapping found" msgstr "Ingen knappbindning hittades" #: data/ui/ButtonDialog.ui:421 msgid "Try a different search" msgstr "Prova en annan sökning" #: data/ui/ErrorPerspective.ui:16 msgid "Here, rodent, rodent, rodent…" msgstr "Hit, gnagare, gnagare, gnagare..." #: data/ui/ErrorPerspective.ui:69 msgid "Uh Oh! Something went wrong…" msgstr "Oj då! Något gick fel..." #: data/ui/ErrorPerspective.ui:73 data/ui/WelcomePerspective.ui:123 msgid "Quit" msgstr "Avsluta" #: data/ui/LedDialog.ui:58 data/ui/LedDialog.ui:209 msgid "Choose a color for the LED" msgstr "Välj en färg för lysdioden" #: data/ui/LedDialog.ui:90 data/ui/LedDialog.ui:257 msgid "Choose a brightness for the LED" msgstr "Välj en ljusstyrka för lysdioden" #: data/ui/LedDialog.ui:104 data/ui/LedDialog.ui:270 msgid "Brightness" msgstr "Ljusstyrka" #: data/ui/LedDialog.ui:135 data/ui/LedDialog.ui:301 msgid "Choose an effect duration for the LED" msgstr "Välj en effektfrekvens för lysdioden" #: data/ui/LedDialog.ui:153 data/ui/LedDialog.ui:319 msgid "ms" msgstr "ms" #: data/ui/LedDialog.ui:175 data/ui/LedDialog.ui:341 msgid "Effect duration" msgstr "Effektfrekvens" #: data/ui/LedDialog.ui:212 msgid "Pick a Color for the LED" msgstr "Välj en färg för lysdioden" #: data/ui/LedDialog.ui:226 msgid "Color" msgstr "Färg" #: data/ui/LedDialog.ui:380 msgid "This LED is off" msgstr "Den här lysdioden är av" #: data/ui/MousePerspective.ui:44 msgid "Something went wrong. The device has been reset to a previous state." msgstr "Något gick fel. Enheten återställdes till ett tidigare tillstand." #: data/ui/MousePerspective.ui:101 msgid "Select another profile" msgstr "Välj en annan profil" #: data/ui/MousePerspective.ui:126 msgid "Commit the changes to the device" msgstr "Utför förändringarna i enheten" #: data/ui/MousePerspective.ui:170 msgid "Click to switch to another profile" msgstr "Klicka för att växla till en annan profil" #: data/ui/MousePerspective.ui:185 msgid "Add profile" msgstr "Lägg till profil" #: data/ui/MousePerspective.ui:189 msgid "Add a new profile to the device" msgstr "Lägg till en ny profil till enheten" #: data/ui/OptionButton.ui:9 msgid "Open the configuration dialog" msgstr "Öppna konfigurationsdialogen" #: data/ui/ProfileRow.ui:16 msgid "Remove this profile from the device" msgstr "Ta bort den här profilen från enheten" #. Translators: this is used to indicate the active resolution. #: data/ui/ResolutionRow.ui:37 msgid "Active" msgstr "Aktiv" #: data/ui/ResolutionRow.ui:77 msgid "Set this resolution’s DPI" msgstr "Ange den här upplösningens DPI" #. Translators: the rate at which the device reports movement. #: data/ui/ResolutionsPage.ui:43 msgid "Report rate" msgstr "Poll frekvens" #: data/ui/ResolutionsPage.ui:60 msgid "Change the profile’s report rate" msgstr "Ändra profilens poll frekvens" #: data/ui/ResolutionsPage.ui:105 msgid "Hz" msgstr "Hz" #. Translators: the sensitivity of the device's sensor. #: data/ui/ResolutionsPage.ui:125 msgid "Sensitivity" msgstr "Känslighet" #: data/ui/ResolutionsPage.ui:174 msgid "Add a new resolution to the profile" msgstr "Lägg till en ny upplösning för profilen" #: data/ui/WelcomePerspective.ui:20 msgid "Welcome" msgstr "Välkommen" #: data/ui/WelcomePerspective.ui:38 msgctxt "A subtitle under the \"Welcome\" title." msgid "Select a device to configure it" msgstr "Välj en enhet för att konfigurera den" #: data/ui/WelcomePerspective.ui:89 msgctxt "A tooltip over the list of devices." msgid "Select a device to configure it" msgstr "Välj en enhet för att konfigurera den" #: data/ui/WelcomePerspective.ui:119 msgid "Select a Device" msgstr "Välj en enhet" #: data/ui/Window.ui:8 msgid "_About Piper" msgstr "_Om" #~ msgid "Profile {}" #~ msgstr "Profil {}" #~ msgid "_Quit" #~ msgstr "_Avsluta" #~ msgid "Failed to commit changes to the device" #~ msgstr "Misslyckades med att utföra förändringarna i enheten" #~ msgid "Remove this resolution from the profile" #~ msgstr "Ta bort den här upplösningen från profilen" piper-0.8/po/uk_UA.po000066400000000000000000000413071467456234500145070ustar00rootroot00000000000000# Ukrainian translation for Piper. # Copyright © 2017-2021 the piper authors. # This file is distributed under the same license as the piper package. # Kyrylo Domskyi , 2021. # #, fuzzy msgid "" msgstr "" "Project-Id-Version: piper\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2021-08-17 22:40+0300\n" "PO-Revision-Date: 2021-08-17 23:48+0300\n" "Last-Translator: Kyrylo Domskyi \n" "Language-Team: \n" "Language: uk_UA\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: data/org.freedesktop.Piper.desktop.in:3 #: data/org.freedesktop.Piper.appdata.xml.in.in:7 msgid "Piper" msgstr "Piper" #: data/org.freedesktop.Piper.desktop.in:4 #: data/org.freedesktop.Piper.appdata.xml.in.in:8 msgid "Configurable mouse configuration utility" msgstr "Налаштовуємий додаток для налаштування миші" #. Translators: Search terms to find this application. Do NOT translate or localize the semicolons! The list MUST also end with a semicolon! #: data/org.freedesktop.Piper.desktop.in:12 msgid "gaming;configuration;mouse;mice;" msgstr "ігри;ґеймінг;налаштування;конфіґурація;миша;" #: data/org.freedesktop.Piper.appdata.xml.in.in:10 msgid "" "Piper is a graphical user interface to configure gaming mice. Configuration " "options include changing the resolution (DPI) of the mouse, adding and " "removing profiles, setting LED colors and changing button behaviors." msgstr "" "Piper це ґрафічний інтерфейс для налаштування ігрової миші. Опції " "налаштувань включають зміну роздільної здатности (DPI) миші, додання і " "видалення профілей, налаштування LED підсвітки і зміни поведінки клавіш." #: data/org.freedesktop.Piper.appdata.xml.in.in:16 msgid "" "Piper requires libratbag’s ratbagd, the daemon to actually communicate with " "the mice. Piper is merely a front end to ratbagd, ratbagd must be installed " "and running when Piper is launched." msgstr "" "Piper потребує бібліотеку libratbagd від сервісу ratbagd, щоб комунікувати з " "мишою. Piper це просто ґрафічний інтерфейс, ratbagd має бути встановлений " "і запущений перед запуском Piper." #: data/org.freedesktop.Piper.appdata.xml.in.in:27 msgid "The button configuraton page" msgstr "Сторінка налаштування клавіш" #: data/org.freedesktop.Piper.appdata.xml.in.in:31 msgid "The LED configuraton page" msgstr "Сторінка налаштування LED підсвітки" #: data/org.freedesktop.Piper.appdata.xml.in.in:35 msgid "The resolution configuraton page" msgstr "Сторінка налаштування роздільної здатности" #. Translators: section header for mapping one button's click to another. #: piper/buttondialog.py:127 msgid "Button mapping" msgstr "Прив'язка клавіш" #. Translators: section header for assigning special functions to buttons. #: piper/buttondialog.py:136 msgid "Special mapping" msgstr "Особлива прив'язка" #. Translators: the {} will be replaced with the button index, e.g. #. "Button 1 click". #: piper/buttondialog.py:208 piper/buttonspage.py:76 msgid "Button {} click" msgstr "Клік клавіші {}" #: piper/buttonspage.py:80 msgid "Macro: {}" msgstr "Макрос: {}" #. Translators: the button is turned disabled, e.g. off. #: piper/buttonspage.py:83 msgid "Disabled" msgstr "Вимкнена" #. Translators: the button has an unknown function. #: piper/buttonspage.py:86 piper/ratbagd.py:665 msgid "Unknown" msgstr "Невідомо" #: piper/buttonspage.py:94 msgid "Configure button {}" msgstr "Налаштувати клавішу {}" #: piper/mouseperspective.py:76 data/ui/ResolutionsPage.ui:209 msgid "Resolutions" msgstr "Роздільна здатність" #: piper/mouseperspective.py:78 msgid "Buttons" msgstr "Клавіші" #: piper/mouseperspective.py:80 msgid "LEDs" msgstr "LED підсвітка" #: piper/ratbagd.py:655 msgid "Left mouse button click" msgstr "Ліва клавіша миші" #: piper/ratbagd.py:656 msgid "Right mouse button click" msgstr "Права клавіша миші" #: piper/ratbagd.py:657 msgid "Middle mouse button click" msgstr "Середня клавіша миші" #: piper/ratbagd.py:658 msgid "Backward" msgstr "Назад" #: piper/ratbagd.py:659 msgid "Forward" msgstr "Вперед" #: piper/ratbagd.py:664 msgid "Invalid" msgstr "Несправжній" #: piper/ratbagd.py:666 msgid "Doubleclick" msgstr "Подвійний клік" #: piper/ratbagd.py:667 msgid "Wheel Left" msgstr "Колесо наліво" #: piper/ratbagd.py:668 msgid "Wheel Right" msgstr "Колесо направо" #: piper/ratbagd.py:669 msgid "Wheel Up" msgstr "Колесо вгору" #: piper/ratbagd.py:670 msgid "Wheel Down" msgstr "Колесо вниз" #: piper/ratbagd.py:671 msgid "Ratchet Mode" msgstr "Режим тріскачки" #: piper/ratbagd.py:672 msgid "Cycle Resolution Up" msgstr "Циклічно збільшити роздільну здатність" #: piper/ratbagd.py:673 msgid "Cycle Resolution Down" msgstr "Циклічно зменшити роздільну здатність" #: piper/ratbagd.py:674 msgid "Resolution Up" msgstr "Збільшити роздільну здатність" #: piper/ratbagd.py:675 msgid "Resolution Down" msgstr "Зденшити роздільну здатність" #: piper/ratbagd.py:676 msgid "Resolution Switch" msgstr "Перемкнути роздільну здатність" #: piper/ratbagd.py:677 msgid "Default Resolution" msgstr "Стандартна роздільна здатність" #: piper/ratbagd.py:678 msgid "Cycle Profile Up" msgstr "Циклічно перемкнути на профіль вище" #: piper/ratbagd.py:679 msgid "Cycle Profile Down" msgstr "Циклічно перемкнути на профіль нижче" #: piper/ratbagd.py:680 msgid "Profile Up" msgstr "Перемкнути на профіль вище" #: piper/ratbagd.py:681 msgid "Profile Down" msgstr "Перемкнути на профіль нижче" #: piper/ratbagd.py:682 msgid "Second Mode" msgstr "Другий режим" #: piper/ratbagd.py:683 msgid "Battery Level" msgstr "Рівень батареї" #. Translators: this is used when there is no macro to preview. #: piper/ratbagd.py:813 data/ui/ButtonDialog.ui:106 data/ui/ButtonDialog.ui:187 msgid "None" msgstr "Нічого" #. Translators: the LED is off. #: piper/ratbagd.py:895 data/ui/LedDialog.ui:395 msgid "Off" msgstr "Вимкнути" #. Translators: the LED has a single, solid color. #: piper/ratbagd.py:897 data/ui/LedDialog.ui:66 msgid "Solid" msgstr "Один колір" #. Translators: the LED is cycling between red, green and blue. #: piper/ratbagd.py:899 data/ui/LedDialog.ui:189 msgid "Cycle" msgstr "Циклічна зміна" #. Translators: the LED's is pulsating a single color on different #. brightnesses. #: piper/ratbagd.py:902 data/ui/LedDialog.ui:355 msgid "Breathing" msgstr "Дихання" #: piper/window.py:40 msgid "Cannot connect to ratbagd" msgstr "Неможливо підключитись до ratbagd" #: piper/window.py:41 msgid "" "Please make sure ratbagd is running and your user is in the required group" msgstr "" "Будь ласка затвердьтесь що ratbagd запущений і ваш користувач у відповідній групі" #: piper/window.py:44 msgid "Incompatible ratbagd API version (required: {}, provided: {})" msgstr "Несумісна версія ratbagd API (потрібна: {}, надана: {})" #: piper/window.py:45 msgid "Please update both piper and libratbag to the latest versions" msgstr "Будь ласка оновіть piper і libratbag до останньої версії" #: piper/window.py:59 piper/window.py:113 msgid "Cannot find any devices" msgstr "Не знайдено жодного пристрою" #: piper/window.py:60 piper/window.py:114 msgid "Please make sure your device is supported and plugged in" msgstr "Будь ласка затвердьтесь що пристрій підтримується і підключений" #: piper/window.py:72 msgid "There are unapplied changes. Are you sure you want to quit?" msgstr "Ви маєте неприйняті зміни. Впевнені що хочете вийти?" #: piper/window.py:81 msgid "Ooops. ratbagd has disappeared" msgstr "Упс. ratbagd зник" #: piper/window.py:82 msgid "Please restart Piper" msgstr "Будь ласка перезапустіть Piper" #. The current device disconnected, which can only happen from the #. mouse perspective as we'd otherwise be in the welcome screen with #. more than one device remaining. Hence, we display the error #. perspective. #: piper/window.py:105 msgid "Your device disconnected!" msgstr "Ваш пристрій відключено!" #: piper/window.py:106 msgid "Please make sure your device is plugged in" msgstr "Будь ласка затвердьтесь що ваш пристій підключений" #: piper/window.py:145 msgid "Cannot display device SVG" msgstr "Не вдається показати SVG пристрою" #: piper/window.py:152 msgid "Newer version of ratbagd required" msgstr "Вимагається новіша версія ratbagd" #: piper/window.py:153 msgid "Please update to the latest available version" msgstr "Будь ласка оновіться до останньої доступної версії" #: piper/window.py:155 msgid "Unknown exception occurred" msgstr "Відбулася невідома помилка" #: data/ui/AboutDialog.ui.in:10 msgid "Version: @version@" msgstr "Версія: @version@" #: data/ui/AboutDialog.ui.in:12 msgid "Visit Piper on GitHub" msgstr "Відвідайте Piper на GitHub" #: data/ui/AboutDialog.ui.in:13 msgid "translator-credits" msgstr "Kyrylo Domskyi " #: data/ui/ButtonDialog.ui:65 msgid "Search for a button mapping" msgstr "Пошук для прив'язки клавіш" #: data/ui/ButtonDialog.ui:91 msgid "Capture a macro for this button" msgstr "Записати макрос для цієї клавіші" #: data/ui/ButtonDialog.ui:104 msgid "The currently set macro" msgstr "Наразі встановлений макрос" #: data/ui/ButtonDialog.ui:129 msgid "Send keystroke" msgstr "Надіслати натиск клавіші" #: data/ui/ButtonDialog.ui:169 msgid "Enter a new key sequence for the macro." msgstr "Введіть нову послідовність клавіш для макросу." #: data/ui/ButtonDialog.ui:235 msgid "Set the device’s handedness." msgstr "Ліва/Права рука" #: data/ui/ButtonDialog.ui:253 msgid "" "This allows you to swap the order of the primary mouse buttons. In left-" "handed mode, the physical left mouse button generates a right mouse click " "and vice versa." msgstr "" "Це дозволяє змінити порядок основних кнопок миші. В режимі для" "лівші фізична ліва кнопка ґенеруватиме правий клік і навпаки." #: data/ui/ButtonDialog.ui:273 msgid "Left Handed" msgstr "Лівша" #: data/ui/ButtonDialog.ui:278 msgid "The left mouse button generates a left mouse click" msgstr "Ліва клавіша миші ґенерує лівий клік" #: data/ui/ButtonDialog.ui:292 msgid "Right Handed" msgstr "Правша" #: data/ui/ButtonDialog.ui:297 msgid "The left mouse button generates a right mouse click" msgstr "Ліва клавіша миші ґенерує правий клік" #: data/ui/ButtonDialog.ui:337 data/ui/LedDialog.ui:414 msgid "Cancel" msgstr "Скасувати" #: data/ui/ButtonDialog.ui:339 data/ui/LedDialog.ui:418 msgid "Ignore any changes made" msgstr "Іґнорувати будь які зроблені зміни" #: data/ui/ButtonDialog.ui:345 data/ui/LedDialog.ui:430 #: data/ui/MousePerspective.ui:132 msgid "Apply" msgstr "Застосувати" #: data/ui/ButtonDialog.ui:348 data/ui/LedDialog.ui:435 msgid "Apply any changes made" msgstr "Застосувати будь які зроблені зміни" #: data/ui/ButtonDialog.ui:388 msgid "No button mapping found" msgstr "Не знайдено жодних прив'язань" #: data/ui/ButtonDialog.ui:404 msgid "Try a different search" msgstr "Спробуйте инше слово для пошуку" #: data/ui/ErrorPerspective.ui:16 msgid "Here, rodent, rodent, rodent…" msgstr "Тут миша, миша, миша..." #: data/ui/ErrorPerspective.ui:69 msgid "Uh Oh! Something went wrong…" msgstr "Уф. Щось пішло не так." #: data/ui/ErrorPerspective.ui:73 data/ui/WelcomePerspective.ui:123 msgid "Quit" msgstr "Вийти" #: data/ui/LedDialog.ui:58 data/ui/LedDialog.ui:209 msgid "Choose a color for the LED" msgstr "Оберіть колір для LED" #: data/ui/LedDialog.ui:90 data/ui/LedDialog.ui:257 msgid "Choose a brightness for the LED" msgstr "Оберіть яскравість для LED" #: data/ui/LedDialog.ui:104 data/ui/LedDialog.ui:270 msgid "Brightness" msgstr "Яскравість" #: data/ui/LedDialog.ui:135 data/ui/LedDialog.ui:301 msgid "Choose an effect duration for the LED" msgstr "Оберіть тривалість ефекту для LED" #: data/ui/LedDialog.ui:153 data/ui/LedDialog.ui:319 msgid "ms" msgstr "мс" #: data/ui/LedDialog.ui:175 data/ui/LedDialog.ui:341 msgid "Effect duration" msgstr "Тривалість ефекту" #: data/ui/LedDialog.ui:212 msgid "Pick a Color for the LED" msgstr "Оберіть колір для LED" #: data/ui/LedDialog.ui:226 msgid "Color" msgstr "Колір" #: data/ui/LedDialog.ui:380 msgid "This LED is off" msgstr "Цей LED вимкнений" #: data/ui/MousePerspective.ui:44 msgid "Something went wrong. The device has been reset to a previous state." msgstr "Щось пішло не так. Пристрій був відновлений до попереднього стану." #: data/ui/MousePerspective.ui:101 msgid "Select another profile" msgstr "Оберіть инший профіль" #: data/ui/MousePerspective.ui:126 msgid "Commit the changes to the device" msgstr "Застосувати зміни до пристроя" #: data/ui/MousePerspective.ui:170 msgid "Click to switch to another profile" msgstr "Натисніть щоб перемкнутись на инший профіль" #: data/ui/MousePerspective.ui:185 msgid "Add profile" msgstr "Додати профіль" #: data/ui/MousePerspective.ui:189 msgid "Add a new profile to the device" msgstr "Додати новий пррофіль до цього пристрою" #: data/ui/OptionButton.ui:9 msgid "Open the configuration dialog" msgstr "Відкрити вікно конфіґурації" #: data/ui/ProfileRow.ui:16 msgid "Remove this profile from the device" msgstr "Видалити цей профіль з пристрою" #. Translators: this is used to indicate the active resolution. #: data/ui/ResolutionRow.ui:37 msgid "Active" msgstr "Активний" #: data/ui/ResolutionRow.ui:77 msgid "Set this resolution’s DPI" msgstr "Застосувати роздільну здатність DPI" #. Translators: the rate at which the device reports movement. #: data/ui/ResolutionsPage.ui:43 msgid "Report rate" msgstr "Швидкість відгуку" #: data/ui/ResolutionsPage.ui:60 msgid "Change the profile’s report rate" msgstr "Змінити швидкість відгуку профіля" #: data/ui/ResolutionsPage.ui:105 msgid "Hz" msgstr "Гц" #. Translators: the sensitivity of the device's sensor. #: data/ui/ResolutionsPage.ui:125 msgid "Sensitivity" msgstr "Чутливість" #: data/ui/ResolutionsPage.ui:174 msgid "Add a new resolution to the profile" msgstr "Додати нову роздільну здатність до цього профілю" #: data/ui/WelcomePerspective.ui:20 msgid "Welcome" msgstr "Вітаємо" #: data/ui/WelcomePerspective.ui:38 msgctxt "A subtitle under the \"Welcome\" title." msgid "Select a device to configure it" msgstr "Оберіть пристрій щоб його налаштувати" #: data/ui/WelcomePerspective.ui:89 msgctxt "A tooltip over the list of devices." msgid "Select a device to configure it" msgstr "Оберіть пристрій щоб його налаштувати" #: data/ui/WelcomePerspective.ui:119 msgid "Select a Device" msgstr "Оберіть пристрій" #: data/ui/Window.ui:8 msgid "_About Piper" msgstr "_Про Piper" piper-0.8/po/zh_CN.po000066400000000000000000000340451467456234500145050ustar00rootroot00000000000000# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the piper package. # # SPDX-FileCopyrightText: 2023 detiam msgid "" msgstr "" "Project-Id-Version: piper\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2023-09-11 20:31+0800\n" "PO-Revision-Date: 2023-09-11 20:43+0800\n" "Last-Translator: detiam \n" "Language-Team: Chinese \n" "Language: zh_CN\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" "X-Generator: Lokalize 23.08.0\n" #: data/org.freedesktop.Piper.desktop.in:3 msgid "Piper" msgstr "Piper" #: data/org.freedesktop.Piper.desktop.in:4 msgid "Configurable mouse configuration utility" msgstr "可配置的鼠标配置工具" #. Translators: Search terms to find this application. Do NOT translate or localize the semicolons! The list MUST also end with a semicolon! #: data/org.freedesktop.Piper.desktop.in:12 msgid "gaming;configuration;mouse;mice;" msgstr "游戏;配置;鼠标;gaming;configuration;mouse;mice;" #: data/org.freedesktop.Piper.appdata.xml.in.in:8 msgid "Gaming mouse configuration utility" msgstr "游戏鼠标配置工具" #: data/org.freedesktop.Piper.appdata.xml.in.in:10 msgid "" "Piper is a graphical user interface to configure gaming mice. Configuration " "options include changing the resolution (DPI) of the mouse, adding and " "removing profiles, setting LED colors and changing button behaviors." msgstr "" "Piper 是一个用来配置游戏鼠标的图形化的用户界面。可配置项包括修改鼠标分辨率" "(DPI),增改配置档,修改灯光颜色和修改按钮行为。" #: data/org.freedesktop.Piper.appdata.xml.in.in:16 msgid "" "Piper requires libratbag’s ratbagd, the daemon to actually communicate with " "the mice. Piper is merely a front end to ratbagd, ratbagd must be installed " "and running when Piper is launched." msgstr "" "Piper 需要 libratbag 的 ratbagd,这个实际与鼠标通讯的守护进程,Piper只是 " "ratbagd 的前端,需要和 ratbagd 同时安装和运行。" #: data/org.freedesktop.Piper.appdata.xml.in.in:27 msgid "The button configuraton page" msgstr "鼠标设置页面" #: data/org.freedesktop.Piper.appdata.xml.in.in:31 msgid "The LED configuraton page" msgstr "灯光设置页面" #: data/org.freedesktop.Piper.appdata.xml.in.in:35 msgid "The resolution configuraton page" msgstr "分辨率设置页面" #. Translators: section header for mapping one button's click to another. #: piper/buttondialog.py:127 msgid "Button mapping" msgstr "按钮映射" #. Translators: section header for assigning special functions to buttons. #: piper/buttondialog.py:136 msgid "Special mapping" msgstr "特殊映射" #. Translators: the {} will be replaced with the button index, e.g. #. "Button 1 click". #: piper/buttondialog.py:208 piper/buttonspage.py:76 msgid "Button {} click" msgstr "按钮 {} 点击" #: piper/buttonspage.py:80 msgid "Macro: {}" msgstr "宏:{}" #. Translators: the button is turned disabled, e.g. off. #: piper/buttonspage.py:83 msgid "Disabled" msgstr "关闭" #. Translators: the button has an unknown function. #: piper/buttonspage.py:86 piper/ratbagd.py:669 msgid "Unknown" msgstr "未知" #: piper/buttonspage.py:94 msgid "Configure button {}" msgstr "配置按钮 {}" #: piper/mouseperspective.py:76 data/ui/ResolutionsPage.ui:240 msgid "Resolutions" msgstr "分辨率" #: piper/mouseperspective.py:78 msgid "Buttons" msgstr "按钮" #: piper/mouseperspective.py:80 msgid "LEDs" msgstr "灯光" #: piper/ratbagd.py:659 msgid "Left mouse button click" msgstr "鼠标左键点击" #: piper/ratbagd.py:660 msgid "Right mouse button click" msgstr "鼠标右键点击" #: piper/ratbagd.py:661 msgid "Middle mouse button click" msgstr "鼠标中键点击" #: piper/ratbagd.py:662 msgid "Backward" msgstr "返回" #: piper/ratbagd.py:663 msgid "Forward" msgstr "前进" #: piper/ratbagd.py:668 msgid "Invalid" msgstr "无效" #: piper/ratbagd.py:670 msgid "Doubleclick" msgstr "双击" #: piper/ratbagd.py:671 msgid "Wheel Left" msgstr "滚轮左" #: piper/ratbagd.py:672 msgid "Wheel Right" msgstr "滚轮右" #: piper/ratbagd.py:673 msgid "Wheel Up" msgstr "滚轮上" #: piper/ratbagd.py:674 msgid "Wheel Down" msgstr "滚轮下" #: piper/ratbagd.py:675 msgid "Ratchet Mode" msgstr "棘轮模式" #: piper/ratbagd.py:676 msgid "Cycle Resolution Up" msgstr "循环分辨率提高" #: piper/ratbagd.py:677 msgid "Cycle Resolution Down" msgstr "循环分辨率下降" #: piper/ratbagd.py:678 msgid "Resolution Up" msgstr "分辨率提高" #: piper/ratbagd.py:679 msgid "Resolution Down" msgstr "分辨率下降" #: piper/ratbagd.py:680 msgid "Resolution Switch" msgstr "分辨率切换" #: piper/ratbagd.py:681 msgid "Default Resolution" msgstr "默认分辨率" #: piper/ratbagd.py:682 msgid "Cycle Profile Up" msgstr "循环配置档向上" #: piper/ratbagd.py:683 msgid "Cycle Profile Down" msgstr "循环配置档向下" #: piper/ratbagd.py:684 msgid "Profile Up" msgstr "配置档向上" #: piper/ratbagd.py:685 msgid "Profile Down" msgstr "配置档向下" #: piper/ratbagd.py:686 msgid "Second Mode" msgstr "第二模式" #: piper/ratbagd.py:687 msgid "Battery Level" msgstr "电池电量" #. Translators: this is used when there is no macro to preview. #: piper/ratbagd.py:817 data/ui/ButtonDialog.ui:106 data/ui/ButtonDialog.ui:187 msgid "None" msgstr "无" #. Translators: the LED is off. #: piper/ratbagd.py:899 data/ui/LedDialog.ui:395 msgid "Off" msgstr "关闭" #. Translators: the LED has a single, solid color. #: piper/ratbagd.py:901 data/ui/LedDialog.ui:66 msgid "Solid" msgstr "单色" #. Translators: the LED is cycling between red, green and blue. #: piper/ratbagd.py:903 data/ui/LedDialog.ui:189 msgid "Cycle" msgstr "循环" #. Translators: the LED's is pulsating a single color on different #. brightnesses. #: piper/ratbagd.py:906 data/ui/LedDialog.ui:355 msgid "Breathing" msgstr "呼吸" #: piper/window.py:42 msgid "Cannot connect to ratbagd" msgstr "无法连接到 ratbagd" #: piper/window.py:43 msgid "" "Please make sure ratbagd is running and your user is in the required group" msgstr "请确定 ratbagd 正在运行并且您的用户在所需的组中" #: piper/window.py:46 msgid "Incompatible ratbagd API version (required: {}, provided: {})" msgstr "不兼容的 ratbagd API 版本 (需要: {}, 提供: {})" #: piper/window.py:47 msgid "Please update both piper and libratbag to the latest versions" msgstr "请更新 Piper 和 libratbag 到最新的版本" #: piper/window.py:61 piper/window.py:115 msgid "Cannot find any devices" msgstr "无法找到任何设备" #: piper/window.py:62 piper/window.py:116 msgid "Please make sure your device is supported and plugged in" msgstr "请确保您的设备是支持的并且已插入到位" #: piper/window.py:74 msgid "There are unapplied changes. Are you sure you want to quit?" msgstr "有未保存的更改,您确定要退出吗?" #: piper/window.py:83 msgid "Ooops. ratbagd has disappeared" msgstr "哦不,ratbagd 消失了" #: piper/window.py:84 msgid "Please restart Piper" msgstr "请重启 Piper" #. The current device disconnected, which can only happen from the #. mouse perspective as we'd otherwise be in the welcome screen with #. more than one device remaining. Hence, we display the error #. perspective. #: piper/window.py:107 msgid "Your device disconnected!" msgstr "您的设备断开了" #: piper/window.py:108 msgid "Please make sure your device is plugged in" msgstr "请确保您的设备已插入到位" #: piper/window.py:147 msgid "Cannot display device SVG" msgstr "无法显示设备 SVG" #: piper/window.py:154 msgid "Newer version of ratbagd required" msgstr "需要更新版本的 ratbagd" #: piper/window.py:155 msgid "Please update to the latest available version" msgstr "请更新到最新可用的版本" #: piper/window.py:157 msgid "Unknown exception occurred" msgstr "遇到未知的异常" #: data/ui/AboutDialog.ui.in:10 msgid "Version: @version@" msgstr "版本: @version@" #: data/ui/AboutDialog.ui.in:12 msgid "Visit Piper on GitHub" msgstr "在 GitHub 查看 Piper" #: data/ui/AboutDialog.ui.in:13 msgid "translator-credits" msgstr "detiam ,2023" #: data/ui/ButtonDialog.ui:65 msgid "Search for a button mapping" msgstr "搜索按钮映射" #: data/ui/ButtonDialog.ui:91 msgid "Capture a macro for this button" msgstr "为这个按钮录制宏" #: data/ui/ButtonDialog.ui:104 msgid "The currently set macro" msgstr "当前设置的宏" #: data/ui/ButtonDialog.ui:129 msgid "Send keystroke" msgstr "发送键盘输入" #: data/ui/ButtonDialog.ui:169 msgid "Enter a new key sequence for the macro." msgstr "为宏输入新的键序" #: data/ui/ButtonDialog.ui:235 msgid "Set the device’s handedness." msgstr "设置设备的惯用手。" #: data/ui/ButtonDialog.ui:253 msgid "" "This allows you to swap the order of the primary mouse buttons. In left-" "handed mode, the physical left mouse button generates a right mouse click " "and vice versa." msgstr "这允许您设置主鼠标键。在左惯用手模式,物理左键会产生右键点击,反之亦然。" #: data/ui/ButtonDialog.ui:273 msgid "Left Handed" msgstr "左惯用手" #: data/ui/ButtonDialog.ui:278 msgid "The left mouse button generates a left mouse click" msgstr "物理左键会产生右键点击" #: data/ui/ButtonDialog.ui:292 msgid "Right Handed" msgstr "右惯用手" #: data/ui/ButtonDialog.ui:297 msgid "The left mouse button generates a right mouse click" msgstr "物理左键会产生左键点击" #: data/ui/ButtonDialog.ui:337 data/ui/LedDialog.ui:414 msgid "Cancel" msgstr "取消" #: data/ui/ButtonDialog.ui:339 data/ui/LedDialog.ui:418 msgid "Ignore any changes made" msgstr "忽略所有更改" #: data/ui/ButtonDialog.ui:345 data/ui/LedDialog.ui:430 #: data/ui/MousePerspective.ui:132 msgid "Apply" msgstr "应用" #: data/ui/ButtonDialog.ui:348 data/ui/LedDialog.ui:435 msgid "Apply any changes made" msgstr "应用并修改模式" #: data/ui/ButtonDialog.ui:388 msgid "No button mapping found" msgstr "没有发现按键映射" #: data/ui/ButtonDialog.ui:404 msgid "Try a different search" msgstr "尝试不同的搜索" #: data/ui/ErrorPerspective.ui:16 msgid "Here, rodent, rodent, rodent…" msgstr "这,咔,咔,咔。。。" #: data/ui/ErrorPerspective.ui:69 msgid "Uh Oh! Something went wrong…" msgstr "嗯、哦,发生了点问题。。。" #: data/ui/ErrorPerspective.ui:73 data/ui/WelcomePerspective.ui:123 msgid "Quit" msgstr "退出" #: data/ui/LedDialog.ui:58 data/ui/LedDialog.ui:209 msgid "Choose a color for the LED" msgstr "为 LED 选择颜色" #: data/ui/LedDialog.ui:90 data/ui/LedDialog.ui:257 msgid "Choose a brightness for the LED" msgstr "为 LED 选择亮度" #: data/ui/LedDialog.ui:104 data/ui/LedDialog.ui:270 msgid "Brightness" msgstr "亮度" #: data/ui/LedDialog.ui:135 data/ui/LedDialog.ui:301 msgid "Choose an effect duration for the LED" msgstr "为 LED 选择效果持续时间" #: data/ui/LedDialog.ui:153 data/ui/LedDialog.ui:319 msgid "ms" msgstr "毫秒" #: data/ui/LedDialog.ui:175 data/ui/LedDialog.ui:341 msgid "Effect duration" msgstr "持续时间" #: data/ui/LedDialog.ui:212 msgid "Pick a Color for the LED" msgstr "选择 LED 颜色" #: data/ui/LedDialog.ui:226 msgid "Color" msgstr "颜色" #: data/ui/LedDialog.ui:380 msgid "This LED is off" msgstr "此 LED 已关闭" #: data/ui/MousePerspective.ui:44 msgid "Something went wrong. The device has been reset to a previous state." msgstr "有错误发生,此设备已被重置为之前的状态。" #: data/ui/MousePerspective.ui:101 msgid "Select another profile" msgstr "选择另一个配置档" #: data/ui/MousePerspective.ui:126 msgid "Commit the changes to the device" msgstr "提交对此设备的修改" #: data/ui/MousePerspective.ui:170 msgid "Click to switch to another profile" msgstr "点击以切换配置档" #: data/ui/MousePerspective.ui:185 msgid "Add profile" msgstr "添加配置档" #: data/ui/MousePerspective.ui:189 msgid "Add a new profile to the device" msgstr "添加一个新的配置档到此设备" #: data/ui/OptionButton.ui:9 msgid "Open the configuration dialog" msgstr "打开配置对话框" #: data/ui/ProfileRow.ui:16 msgid "Remove this profile from the device" msgstr "删除一个此设备上的配置档" #. Translators: this is used to indicate the active resolution. #: data/ui/ResolutionRow.ui:37 msgid "Active" msgstr "激活" #: data/ui/ResolutionRow.ui:77 msgid "Set this resolution’s DPI" msgstr "设置这个分辨率的 DPI" #. Translators: the rate at which the device reports movement. #: data/ui/ResolutionsPage.ui:43 msgid "Report rate" msgstr "回报率" #: data/ui/ResolutionsPage.ui:60 msgid "Change the profile’s report rate" msgstr "修改这个配置档的回报率" #: data/ui/ResolutionsPage.ui:136 msgid "Hz" msgstr "赫兹" #. Translators: the sensitivity of the device's sensor. #: data/ui/ResolutionsPage.ui:156 msgid "Sensitivity" msgstr "灵敏度" #: data/ui/ResolutionsPage.ui:205 msgid "Add a new resolution to the profile" msgstr "为这个配置档增加新的分辨率" #: data/ui/WelcomePerspective.ui:20 msgid "Welcome" msgstr "欢迎" #: data/ui/WelcomePerspective.ui:38 msgctxt "A subtitle under the \"Welcome\" title." msgid "Select a device to configure it" msgstr "选择一个设备来配置" #: data/ui/WelcomePerspective.ui:89 msgctxt "A tooltip over the list of devices." msgid "Select a device to configure it" msgstr "选择一个设备以进行配置" #: data/ui/WelcomePerspective.ui:119 msgid "Select a Device" msgstr "选择设备" #: data/ui/Window.ui:8 msgid "_About Piper" msgstr "关于 Piper [_A]" #~ msgid "Disable" #~ msgstr "禁用" #~ msgid "Other" #~ msgstr "其他" #~ msgid "Key: {}" #~ msgstr "键:{}" #~ msgid "Advanced" #~ msgstr "高级" #~ msgid "Debounce time" #~ msgstr "去抖动时间" #~ msgid "Angle snapping" #~ msgstr "角度锁定" #~ msgid "Disable this resolution" #~ msgstr "禁用此分辨率" #~ msgid "Set active" #~ msgstr "设为激活" #~ msgid "Set this resolution as active" #~ msgstr "设置此分辨率为激活" piper-0.8/po/zh_TW.po000066400000000000000000000337411467456234500145410ustar00rootroot00000000000000# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the piper package. # # Jeff Huang , 2019, 2020. msgid "" msgstr "" "Project-Id-Version: piper\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2020-01-30 11:46+0800\n" "PO-Revision-Date: 2020-01-30 11:51+0800\n" "Last-Translator: Jeff Huang \n" "Language-Team: Chinese \n" "Language: zh_TW\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" "X-Generator: Lokalize 19.08.3\n" #: data/org.freedesktop.Piper.desktop.in:3 #: data/org.freedesktop.Piper.appdata.xml.in.in:7 msgid "Piper" msgstr "Piper" #: data/org.freedesktop.Piper.desktop.in:4 #: data/org.freedesktop.Piper.appdata.xml.in.in:8 msgid "Configurable mouse configuration utility" msgstr "可設定的滑鼠組態實用工具" #. Translators: Do NOT translate or transliterate this text (this is an icon file name)! #: data/org.freedesktop.Piper.desktop.in:7 msgid "org.freedesktop.Piper" msgstr "org.freedesktop.Piper" #. Translators: Search terms to find this application. Do NOT translate or localize the semicolons! The list MUST also end with a semicolon! #: data/org.freedesktop.Piper.desktop.in:12 msgid "gaming;configuration;mouse;mice;" msgstr "gaming;configuration;mouse;mice;" #: data/org.freedesktop.Piper.appdata.xml.in.in:10 msgid "" "Piper is a graphical user interface to configure gaming mice. Configuration " "options include changing the resolution (DPI) of the mouse, adding and " "removing profiles, setting LED colors and changing button behaviors." msgstr "" "Piper 是用來設定遊戲滑鼠的圖形化使用者介面。設定選項包含了變更滑鼠解析度 " "(DPI)、新增與移除設定檔、設定 LED 色彩並變更按鈕行為等等。" #: data/org.freedesktop.Piper.appdata.xml.in.in:16 msgid "" "Piper requires libratbag’s ratbagd, the daemon to actually communicate with " "the mice. Piper is merely a front end to ratbagd, ratbagd must be installed " "and running when Piper is launched." msgstr "" "Piper 依賴於 libratbag 的 ratbagd,這是實際與滑鼠溝通的幕後程式。Piper 只是 " "ratbagd 的前端,ratbagd 必須在 Piper 啟動前安裝並執行。" #: data/org.freedesktop.Piper.appdata.xml.in.in:33 msgid "The button configuraton page" msgstr "按鈕設定頁面" #: data/org.freedesktop.Piper.appdata.xml.in.in:37 msgid "The LED configuraton page" msgstr "LED 設定頁面" #: data/org.freedesktop.Piper.appdata.xml.in.in:41 msgid "The resolution configuraton page" msgstr "解析度設定頁面" #. Translators: section header for mapping one button's click to another. #: piper/buttondialog.py:141 msgid "Button mapping" msgstr "按鈕對映" #. Translators: section header for assigning special functions to buttons. #: piper/buttondialog.py:150 msgid "Special mapping" msgstr "特別對映" #. Translators: the {} will be replaced with the button index, e.g. #. "Button 1 click". #: piper/buttondialog.py:222 piper/buttonspage.py:90 msgid "Button {} click" msgstr "按鈕 {} 點擊" #: piper/buttonspage.py:94 msgid "Macro: {}" msgstr "巨集: {}" #. Translators: the button is turned disabled, e.g. off. #: piper/buttonspage.py:97 msgid "Disabled" msgstr "已停用" #. Translators: the button has an unknown function. #: piper/buttonspage.py:100 piper/ratbagd.py:665 msgid "Unknown" msgstr "未知" #: piper/buttonspage.py:108 msgid "Configure button {}" msgstr "設定按鈕 {}" #: piper/mouseperspective.py:90 data/ui/ResolutionsPage.ui:209 msgid "Resolutions" msgstr "解析度" #: piper/mouseperspective.py:92 msgid "Buttons" msgstr "按鈕" #: piper/mouseperspective.py:94 msgid "LEDs" msgstr "LED" #: piper/ratbagd.py:655 msgid "Left mouse button click" msgstr "點擊滑鼠左鍵" #: piper/ratbagd.py:656 msgid "Right mouse button click" msgstr "點擊滑鼠右鍵" #: piper/ratbagd.py:657 msgid "Middle mouse button click" msgstr "點擊滑鼠中鍵" #: piper/ratbagd.py:658 msgid "Backward" msgstr "往後" #: piper/ratbagd.py:659 msgid "Forward" msgstr "往前" #: piper/ratbagd.py:664 msgid "Invalid" msgstr "無效" #: piper/ratbagd.py:666 msgid "Doubleclick" msgstr "雙擊" #: piper/ratbagd.py:667 msgid "Wheel Left" msgstr "滾輪向左" #: piper/ratbagd.py:668 msgid "Wheel Right" msgstr "滾輪向右" #: piper/ratbagd.py:669 msgid "Wheel Up" msgstr "滾輪向上" #: piper/ratbagd.py:670 msgid "Wheel Down" msgstr "滾輪向下" #: piper/ratbagd.py:671 msgid "Ratchet Mode" msgstr "棘輪模式" #: piper/ratbagd.py:672 msgid "Cycle Resolution Up" msgstr "循環解析度提高" #: piper/ratbagd.py:673 msgid "Cycle Resolution Down" msgstr "循環解析度降低" #: piper/ratbagd.py:674 msgid "Resolution Up" msgstr "解析度提高" #: piper/ratbagd.py:675 msgid "Resolution Down" msgstr "解析度降低" #: piper/ratbagd.py:676 msgid "Resolution Switch" msgstr "解析度切換" #: piper/ratbagd.py:677 msgid "Default Resolution" msgstr "預設解析度" #: piper/ratbagd.py:678 msgid "Cycle Profile Up" msgstr "循環設定檔提高" #: piper/ratbagd.py:679 msgid "Cycle Profile Down" msgstr "循環設定檔降低" #: piper/ratbagd.py:680 msgid "Profile Up" msgstr "設定檔提高" #: piper/ratbagd.py:681 msgid "Profile Down" msgstr "設定檔降低" #: piper/ratbagd.py:682 msgid "Second Mode" msgstr "第二模式" #: piper/ratbagd.py:683 msgid "Battery Level" msgstr "電池電量" #. Translators: this is used when there is no macro to preview. #: piper/ratbagd.py:813 data/ui/ButtonDialog.ui:106 data/ui/ButtonDialog.ui:187 msgid "None" msgstr "無" #. Translators: the LED is off. #: piper/ratbagd.py:895 data/ui/LedDialog.ui:395 msgid "Off" msgstr "關閉" #. Translators: the LED has a single, solid color. #: piper/ratbagd.py:897 data/ui/LedDialog.ui:66 msgid "Solid" msgstr "單色" #. Translators: the LED is cycling between red, green and blue. #: piper/ratbagd.py:899 data/ui/LedDialog.ui:189 msgid "Cycle" msgstr "循環" #. Translators: the LED's is pulsating a single color on different #. brightnesses. #: piper/ratbagd.py:902 data/ui/LedDialog.ui:355 msgid "Breathing" msgstr "呼吸" #: piper/window.py:54 msgid "Cannot connect to ratbagd" msgstr "無法連線至 ratbagd" #: piper/window.py:55 msgid "" "Please make sure ratbagd is running and your user is in the required group" msgstr "請確定 ratbagd 正在執行,且您的使用者位在必要的群組中" #: piper/window.py:58 msgid "Incompatible ratbagd API version (required: {}, provided: {})" msgstr "不相容的 ratbagd API 版本(需要: {},提供: {})" #: piper/window.py:59 msgid "Please update both piper and libratbag to the latest versions" msgstr "請將 piper 與 libratbag 同時更新到最新版本" #: piper/window.py:73 piper/window.py:127 msgid "Cannot find any devices" msgstr "找不到任何裝置" #: piper/window.py:74 piper/window.py:128 msgid "Please make sure your device is supported and plugged in" msgstr "請確定您的裝置已被支援並已插入" #: piper/window.py:86 msgid "There are unapplied changes. Are you sure you want to quit?" msgstr "有尚未套用的變更。您確定您想要離開嗎?" #: piper/window.py:95 msgid "Ooops. ratbagd has disappeared" msgstr "喔喔。ratbagd 消失了" #: piper/window.py:96 msgid "Please restart Piper" msgstr "請重新啟動 Piper" #. The current device disconnected, which can only happen from the #. mouse perspective as we'd otherwise be in the welcome screen with #. more than one device remaining. Hence, we display the error #. perspective. #: piper/window.py:119 msgid "Your device disconnected!" msgstr "您的裝置已斷線!" #: piper/window.py:120 msgid "Please make sure your device is plugged in" msgstr "請確定您的裝置已插入" #: piper/window.py:159 msgid "Cannot display device SVG" msgstr "無法顯示裝置 SVG" #: piper/window.py:166 msgid "Newer version of ratbagd required" msgstr "需要較新的 ratbagd 版本" #: piper/window.py:167 msgid "Please update to the latest available version" msgstr "請更新到可用的最新版本" #: piper/window.py:169 msgid "Unknown exception occurred" msgstr "遇到未知的例外" #: data/ui/AboutDialog.ui.in:10 msgid "Version: @version@" msgstr "版本:@version@" #: data/ui/AboutDialog.ui.in:12 msgid "Visit Piper on GitHub" msgstr "在 GitHub 上造訪 Piper" #: data/ui/AboutDialog.ui.in:13 msgid "translator-credits" msgstr "Jeff Huang , 2019" #: data/ui/ButtonDialog.ui:65 msgid "Search for a button mapping" msgstr "搜尋按鈕對映" #: data/ui/ButtonDialog.ui:91 msgid "Capture a macro for this button" msgstr "捕獲此按鈕的巨集" #: data/ui/ButtonDialog.ui:104 msgid "The currently set macro" msgstr "目前設定的巨集" #: data/ui/ButtonDialog.ui:129 msgid "Send keystroke" msgstr "傳送按鍵" #: data/ui/ButtonDialog.ui:169 msgid "Enter a new key sequence for the macro." msgstr "為巨集輸入新的按鍵序列。" #: data/ui/ButtonDialog.ui:221 msgid "Press Escape to cancel or Return to accept." msgstr "按下 Esc 鍵以取消,或 Enter/Return 鍵以接受。" #: data/ui/ButtonDialog.ui:252 msgid "Set the device’s handedness." msgstr "設定裝置慣用手。" #: data/ui/ButtonDialog.ui:270 msgid "" "This allows you to swap the order of the primary mouse buttons. In left-" "handed mode, the physical left mouse button generates a right mouse click " "and vice versa." msgstr "" "這讓您可以切換滑鼠主要按鍵的順序。在左手模式中,實際上的滑鼠左鍵會生成滑鼠右" "鍵的點擊,反之亦然。" #: data/ui/ButtonDialog.ui:290 msgid "Left Handed" msgstr "左手" #: data/ui/ButtonDialog.ui:295 msgid "The left mouse button generates a left mouse click" msgstr "滑鼠左鍵生成滑鼠左鍵點擊" #: data/ui/ButtonDialog.ui:309 msgid "Right Handed" msgstr "右手" #: data/ui/ButtonDialog.ui:314 msgid "The left mouse button generates a right mouse click" msgstr "滑鼠左鍵生成滑鼠右鍵點擊" #: data/ui/ButtonDialog.ui:354 data/ui/LedDialog.ui:414 msgid "Cancel" msgstr "取消" #: data/ui/ButtonDialog.ui:356 data/ui/LedDialog.ui:418 msgid "Ignore any changes made" msgstr "忽略已作出的任何變更" #: data/ui/ButtonDialog.ui:362 data/ui/LedDialog.ui:430 #: data/ui/MousePerspective.ui:132 msgid "Apply" msgstr "套用" #: data/ui/ButtonDialog.ui:365 data/ui/LedDialog.ui:435 msgid "Apply any changes made" msgstr "套用已作出的任何變更" #: data/ui/ButtonDialog.ui:405 msgid "No button mapping found" msgstr "找不到按鈕對映" #: data/ui/ButtonDialog.ui:421 msgid "Try a different search" msgstr "嘗試不同的搜尋" #: data/ui/ErrorPerspective.ui:16 msgid "Here, rodent, rodent, rodent…" msgstr "這裡,嚼、嚼、嚼……" #: data/ui/ErrorPerspective.ui:69 msgid "Uh Oh! Something went wrong…" msgstr "喔喔!發生了一點問題……" #: data/ui/ErrorPerspective.ui:73 data/ui/WelcomePerspective.ui:123 msgid "Quit" msgstr "離開" #: data/ui/LedDialog.ui:58 data/ui/LedDialog.ui:209 msgid "Choose a color for the LED" msgstr "選擇 LED 的顏色" #: data/ui/LedDialog.ui:90 data/ui/LedDialog.ui:257 msgid "Choose a brightness for the LED" msgstr "選擇 LED 的亮度" #: data/ui/LedDialog.ui:104 data/ui/LedDialog.ui:270 msgid "Brightness" msgstr "亮度" #: data/ui/LedDialog.ui:135 data/ui/LedDialog.ui:301 msgid "Choose an effect duration for the LED" msgstr "選擇 LED 效果的持續時間" #: data/ui/LedDialog.ui:153 data/ui/LedDialog.ui:319 msgid "ms" msgstr "毫秒" #: data/ui/LedDialog.ui:175 data/ui/LedDialog.ui:341 msgid "Effect duration" msgstr "效果持續時間" #: data/ui/LedDialog.ui:212 msgid "Pick a Color for the LED" msgstr "挑選 LED 的顏色" #: data/ui/LedDialog.ui:226 msgid "Color" msgstr "顏色" #: data/ui/LedDialog.ui:380 msgid "This LED is off" msgstr "這個 LED 關掉了" #: data/ui/MousePerspective.ui:44 msgid "Something went wrong. The device has been reset to a previous state." msgstr "發生了一點問題。裝置已被重設回先前的狀態。" #: data/ui/MousePerspective.ui:101 msgid "Select another profile" msgstr "選取其他設定檔" #: data/ui/MousePerspective.ui:126 msgid "Commit the changes to the device" msgstr "遞交變更到裝置" #: data/ui/MousePerspective.ui:170 msgid "Click to switch to another profile" msgstr "點擊以切換到其他設定檔" #: data/ui/MousePerspective.ui:185 msgid "Add profile" msgstr "新增設定檔" #: data/ui/MousePerspective.ui:189 msgid "Add a new profile to the device" msgstr "將新的設定檔新增到裝置" #: data/ui/OptionButton.ui:9 msgid "Open the configuration dialog" msgstr "開啟設定對話框" #: data/ui/ProfileRow.ui:16 msgid "Remove this profile from the device" msgstr "從裝置移除此設定檔" #. Translators: this is used to indicate the active resolution. #: data/ui/ResolutionRow.ui:37 msgid "Active" msgstr "作用中" #: data/ui/ResolutionRow.ui:77 msgid "Set this resolution’s DPI" msgstr "設定此解析度的 DPI" #. Translators: the rate at which the device reports movement. #: data/ui/ResolutionsPage.ui:43 msgid "Report rate" msgstr "回報頻率" #: data/ui/ResolutionsPage.ui:60 msgid "Change the profile’s report rate" msgstr "變更設定檔的回報頻率" #: data/ui/ResolutionsPage.ui:105 msgid "Hz" msgstr "Hz" #. Translators: the sensitivity of the device's sensor. #: data/ui/ResolutionsPage.ui:125 msgid "Sensitivity" msgstr "靈敏度" #: data/ui/ResolutionsPage.ui:174 msgid "Add a new resolution to the profile" msgstr "將新的解析度新增到設定檔中" #: data/ui/WelcomePerspective.ui:20 msgid "Welcome" msgstr "歡迎" #: data/ui/WelcomePerspective.ui:38 msgctxt "A subtitle under the \"Welcome\" title." msgid "Select a device to configure it" msgstr "選取要設定的裝置" #: data/ui/WelcomePerspective.ui:89 msgctxt "A tooltip over the list of devices." msgid "Select a device to configure it" msgstr "選取要設定的裝置" #: data/ui/WelcomePerspective.ui:119 msgid "Select a Device" msgstr "選取裝置" #: data/ui/Window.ui:8 msgid "_About Piper" msgstr "關於 Piper(_A)" piper-0.8/pyproject.toml000066400000000000000000000015161467456234500154370ustar00rootroot00000000000000[tool.black] target-version = ["py37"] [tool.ruff] target-version = "py37" select = [ # pycodestyle "E", "W", # pyflakes "F", # pyupgrade # Use modern Python features for the best possible develop experience. "UP", # flake8-bugbear # Find obvious bugs. "B", # flake8-pie "PIE", # flake8-return "RET", # pep8-naming # `Error` suffix on exception names. "N818", # flake8-simplify "SIM", ] ignore = [ # Line too long. # We have some places where it's just impossible to make it fit. "E501", # Use 'contextlib.suppress(...)' instead of try-except-pass. # I think it's better to use integrated language constructs instead # of libraries. "SIM105", # Use `"key" in dict` instead of `"key" in dict.keys()`. # While the lint itself is good, fixing it's warnings causes `KeyError` # errors with `GLib.Variant`. "SIM118", ] piper-0.8/tests/000077500000000000000000000000001467456234500136625ustar00rootroot00000000000000piper-0.8/tests/check-files-in-git.sh000066400000000000000000000010661467456234500175630ustar00rootroot00000000000000#!/bin/bash # # Usage: check-files-in-git.sh /path/to/piper/ if [ -z "$top_srcdir" ]; then top_srcdir="$1" fi if [ -z "$top_srcdir" ]; then echo "Usage: `basename $0` /path/to/piper" exit 1 fi export GIT_DIR="$top_srcdir/.git"; if ! git ls-files >& /dev/null; then echo "Not a git tree. Skipping" exit 77 fi pushd "$top_srcdir" > /dev/null for file in data/svgs/*.svg; do git ls-files --error-unmatch "$file" &> /dev/null || ( echo "ERROR: File $file is not in git" && test); rc="$(($rc + $?))"; done popd > /dev/null exit $rc piper-0.8/tests/check-svg.py000077500000000000000000000074551467456234500161240ustar00rootroot00000000000000#!/usr/bin/env python3 # vim: set expandtab shiftwidth=4 tabstop=4: import os import sys from lxml import etree from pathlib import Path import logging ns = {"svg": "http://www.w3.org/2000/svg"} style_query = '//svg:rect[@id="{}"][contains(@style, "{}")]' logger = None class SVGLogger(logging.Logger): def __init__(self, name, level=logging.NOTSET): self.success = True return super().__init__(name, level) def error(self, msg, *args, **kwargs): self.success = False return super().error(msg, *args, **kwargs) @classmethod def get_logger(cls, path): logging.setLoggerClass(SVGLogger) logging.basicConfig(level=logging.DEBUG) return logging.getLogger(path) def check_size(root): width = float(root.attrib["width"]) height = float(root.attrib["height"]) if not 400 <= width <= 500: logger.error(f"Width is outside of range: {width}") if not 400 <= height <= 500: logger.error(f"Height is outside of range: {height}") def check_layers(root): """ Check there are layers (well, groups) for the components we require. """ layer_ids = [g.attrib["id"] for g in root.iterfind("svg:g", ns)] for layer in ["Device", "Buttons", "LEDs"]: if layer not in layer_ids: logger.error(f"Missing layer: {layer}") def check_elements(root, prefix, required=0): """ Checks for elements of the form 'prefixN' in the root tag. Any elements found must be consecutive or an warning is printed, i.e. if there's a 'button8' there has to be a 'button7'. If required is nonzero, an error is logged for any missing element with an index less than required. """ # elements can be paths and rects # This includes leaders and lines element_ids = [] for element in ["path", "rect", "g", "circle"]: element_ids += [ p.attrib["id"] for p in root.xpath(f"//svg:{element}", namespaces=ns) if p.attrib["id"].startswith(prefix) ] idx = 0 highest = -1 for idx in range(20): e = f"{prefix}{idx}" previous = f"{prefix}{idx - 1}" leader = f"{prefix}{idx}-leader" path = f"{prefix}{idx}-path" if e in element_ids: highest = idx if idx > 0 and previous not in element_ids: logger.warning(f"Non-consecutive {prefix}: {e}") if leader not in element_ids: logger.error(f"Missing {leader} for {e}") else: element = root.xpath( style_query.format(leader, "text-align"), namespaces=ns ) if element is None or len(element) != 1 or element[0] is None: logger.error(f"Missing style property for {leader}") if path not in element_ids: logger.error(f"Missing {path} for {e}") elif leader in element_ids: logger.error(f"Have {leader} but not {e}") elif path in element_ids: logger.error(f"Have {path} but not {e}") elif idx < required: logger.error(f"Missing {prefix}: {e}") logger.info(f"Found {highest + 1} {prefix}s") def check_leds(root): check_elements(root, "led") def check_buttons(root): check_elements(root, "button") def check_svg(path): path = os.path.join(os.environ.get("BASEDIR", "."), path) svg = etree.parse(path) root = svg.getroot() check_size(root) check_layers(root) check_buttons(root) check_leds(root) if __name__ == "__main__": success = True for path in Path(sys.argv[1]).glob("*.svg"): logger = SVGLogger.get_logger(str(path)) print(f"checking {path}...") check_svg(path) if not logger.success: success = False if not success: sys.exit(1) piper-0.8/tests/python-black-check.sh000077500000000000000000000006451467456234500176740ustar00rootroot00000000000000#!/bin/sh if [ -z "$MESON_SOURCE_ROOT" ]; then echo >&2 "Expected \$MESON_SOURCE_ROOT to be set. Are you sure you are running this through ninja?" exit 100 fi cd "$MESON_SOURCE_ROOT" || exit 101 files=$(git ls-files "*.py" "*.py.in") if [ -z "$files" ]; then echo >&2 "Git didn't find any files" exit 77 fi command -v black >/dev/null 2>&1 || { echo >&2 "black is not installed" exit 77 } black --check $files piper-0.8/tests/python-ruff-check.sh000077500000000000000000000006401467456234500175550ustar00rootroot00000000000000#!/bin/sh if [ -z "$MESON_SOURCE_ROOT" ]; then echo >&2 "Expected \$MESON_SOURCE_ROOT to be set. Are you sure you are running this through ninja?" exit 100 fi cd "$MESON_SOURCE_ROOT" || exit 101 files=$(git ls-files "*.py" "*.py.in") if [ -z "$files" ]; then echo >&2 "Git didn't find any files" exit 77 fi command -v ruff >/dev/null 2>&1 || { echo >&2 "ruff is not installed" exit 77 } ruff check $files piper-0.8/tests/svg-lookup-ini-test.py000077500000000000000000000030151467456234500200760ustar00rootroot00000000000000#!/usr/bin/env python3 import argparse import configparser import unittest import sys from pathlib import Path path = None svgdir = None config = None class TestSVGLookup(unittest.TestCase): def test_has_sections(self): self.assertTrue(config.sections()) def test_required(self): for name in config.sections(): s = config[name] self.assertIn("DeviceMatch", s) self.assertIn("Svg", s) def test_svg_filename(self): svgs = [config[s]["Svg"] for s in config.sections()] for svg in svgs: self.assertTrue(Path(svgdir, svg).exists(), msg=svg) def test_uniq_match(self): matches = [config[s]["DeviceMatch"] for s in config.sections()] d = {} for match in matches: self.assertNotIn(match, d, msg=f'Duplicate match "{match}"') d[match] = True def setUpModule(): global config, path config = configparser.ConfigParser(strict=True) config.optionxform = lambda option: option config.read(path) assert config.sections() def main(): global path, svgdir parser = argparse.ArgumentParser(description="Device data-file checker") parser.add_argument("file", nargs=1, help="Absolute path to svg-lookup.ini") parser.add_argument("svgdir", nargs=1, help="Directory containing svg files") args, remainder = parser.parse_known_args() path = args.file[0] svgdir = args.svgdir[0] unittest.main(argv=[sys.argv[0], *remainder]) if __name__ == "__main__": main() piper-0.8/tools/000077500000000000000000000000001467456234500136605ustar00rootroot00000000000000piper-0.8/tools/python-black.sh000077500000000000000000000006351467456234500166160ustar00rootroot00000000000000#!/bin/sh if [ -z "$MESON_SOURCE_ROOT" ]; then echo >&2 "Expected \$MESON_SOURCE_ROOT to be set. Are you sure you are running this through ninja?" exit 100 fi cd "$MESON_SOURCE_ROOT" || exit 101 files=$(git ls-files "*.py" "*.py.in") if [ -z "$files" ]; then echo >&2 "Git didn't find any files" exit 77 fi command -v black >/dev/null 2>&1 || { echo >&2 "black is not installed" exit 77 } black $files piper-0.8/tools/python-ruff.sh000077500000000000000000000006461467456234500165060ustar00rootroot00000000000000#!/bin/sh if [ -z "$MESON_SOURCE_ROOT" ]; then echo >&2 "Expected \$MESON_SOURCE_ROOT to be set. Are you sure you are running this through ninja?" exit 100 fi cd "$MESON_SOURCE_ROOT" || exit 101 files=$(git ls-files "*.py" "*.py.in") if [ -z "$files" ]; then echo >&2 "Git didn't find any files" exit 77 fi command -v ruff >/dev/null 2>&1 || { echo >&2 "ruff is not installed" exit 77 } ruff check --fix $files