diff --git a/.gitignore b/.gitignore index fbf32cd..ae9e503 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,52 @@ -.* -build -build-* +# Build directories +build/ +build-*/ + +# CMake files +CMakeCache.txt +CMakeFiles/ +cmake_install.cmake +Makefile +*.cmake +!CMakeLists.txt +!cmake/*.cmake + +# Qt Creator files CMakeLists.txt.user +CMakeLists.txt.user.* + +# Compiled Object files +*.o +*.obj + +# Executables +thunderpad +qjoypad + +# Generated MOC files +moc_*.cpp +moc_*.h + +# Generated files +config.h + +# IDE files +.vscode/ +.idea/ +*.pro.user* + +# System files +.DS_Store +Thumbs.db + +# Backup files +*~ +*.bak +*.orig +*.swp +*.tmp + +# Distribution files +*.tar.gz +*.tar.bz2 +*.zip \ No newline at end of file diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..ecf61f0 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,294 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## Project Overview + +**ThunderPad** is an accessibility-focused fork of QJoyPad - a Qt-based Linux application that maps joystick/gamepad inputs to keyboard keys and mouse actions. ThunderPad was completely redesigned for full screen reader compatibility and keyboard navigation support. It's developed for the Stormux project with accessibility as the top priority. + +### Key Differentiators from QJoyPad +- **Full keyboard navigation** - No mouse required for any configuration task +- **Screen reader compatible** - Works seamlessly with Orca and other assistive technologies +- **Window mode by default** - Opens configuration window directly (use `--tray` for system tray) +- **English-only interface** - Translation system removed for simplicity and better screen reader performance +- **Separate config directory** - Uses `~/.config/thunderpad/` to coexist with QJoyPad + +## Critical Development Principle + +**🔴 ACCESSIBILITY FIRST: Screen reader accessibility is the top priority for ANY code changes.** + +All modifications must maintain or improve: +- Complete keyboard navigation (Tab/Shift+Tab/Arrow keys) +- Screen reader compatibility (proper labels, focus management) +- Logical tab order and focus flow +- Accessible widget choices (lists vs. clickable grids) + +## Build System + +This project uses CMake with Qt5 dependencies: + +### Build Commands +```bash +# Standard build process +mkdir build +cd build +cmake .. -DCMAKE_BUILD_TYPE=Release +make -j$(nproc) + +# For installation +make install + +# For development with debug symbols +cmake .. -DCMAKE_BUILD_TYPE=Debug +``` + +### CMake Configuration Options +- `-DDEVICE_DIR=/dev/input` - Set joystick device directory (default: /dev/input) +- `-DWITH_LIBUDEV=OFF` - Disable libudev support for automatic device detection +- `-DPLAIN_KEYS=ON` - Use standard X11 key names instead of readable names +- `-DCMAKE_INSTALL_PREFIX=/usr` - Set installation prefix + +### Dependencies +- Qt5Widgets, Qt5X11Extras +- libudev (optional, for automatic device detection) +- Linux joystick driver support +- For accessibility testing: Orca screen reader + +## Code Architecture + +### Project Rebranding (QJoyPad → ThunderPad) +**Version**: 2025.06.30 +**Executable**: `thunderpad` +**Config Directory**: `~/.config/thunderpad/` +**PID File**: `/tmp/thunderpad.pid` +**Desktop Entry**: `thunderpad.desktop` + +All source code has been systematically updated: +- Header guards: `QJOYPAD_*` → `THUNDERPAD_*` +- Macro definitions: `QJOYPAD_NAME` → `THUNDERPAD_NAME` +- Icon paths: `QJOYPAD_ICON24/64` → `THUNDERPAD_ICON24/64` +- Comments and references updated throughout + +### Core Components + +1. **LayoutManager** (`layout.h/cpp`) - Central coordinator that manages: + - Layout loading/saving to `~/.config/thunderpad/` + - Optional system tray icon and menu (when `--tray` used) + - Configuration window display (default behavior) + - Joystick device detection and management + - Inter-process communication via signals (SIGUSR1/SIGUSR2) + +2. **JoyPad** (`joypad.h/cpp`) - Represents individual joystick devices: + - File descriptor management for `/dev/input/jsX` devices + - Contains collections of Button and Axis objects + - Handles joystick events via QSocketNotifier + +3. **Button** (`button.h/cpp`) - Individual button configuration: + - Key/mouse button mapping + - Sticky mode (toggle on/off) + - Rapid fire functionality + - Layout switching capability + +4. **Axis** (`axis.h/cpp`) - Joystick axis configuration: + - Keyboard key mapping for positive/negative directions + - Mouse movement control (relative/absolute) + - Sensitivity and dead zone settings + - Gradient mode for variable input strength + +5. **Event System** (`event.h/cpp`) - X11 integration for: + - Key press/release simulation + - Mouse button clicks + - Mouse movement + +### Accessibility-Focused UI Components + +**CRITICAL**: All UI components prioritize keyboard navigation and screen reader compatibility. + +- **LayoutEdit** (`layout_edit.h/cpp`) - Main accessible configuration dialog: + - QTabWidget for joystick navigation (replaces clickable FlashRadioArray) + - Layout management controls at top (dropdown, add/remove/rename buttons) + - Import/export functionality + - Save/revert controls + +- **JoyPadWidget** (`joypadw.h/cpp`) - Accessible per-device configuration: + - **Axes list** - QListWidget showing all axes with current assignments + - **Configure Axis button** - Opens configuration for selected axis + - **Buttons list** - QListWidget showing all buttons with current assignments + - **Configure Button button** - Opens configuration for selected button + - **Clear/Quick Set buttons** - Bulk operations + - Explicit tab order with `setTabOrder()` calls + +- **ButtonEdit/AxisEdit** - Component-specific configuration dialogs +- **Icon** - Floating icon alternative (rarely used in accessibility mode) + +### Accessibility Design Patterns +- **QListWidget over clickable grids** - Screen reader navigable +- **Dedicated configure buttons** - Instead of click-to-configure interfaces +- **QTabWidget for device switching** - Keyboard accessible tabs +- **Explicit tab order** - `setTabOrder()` calls ensure logical navigation +- **Descriptive widget names** - Proper accessibility labels +- **Qt::StrongFocus policy** - Ensures all interactive elements are keyboard reachable + +## Development Workflows + +### Testing Changes +```bash +# Build and run locally (default: window mode) +make +./thunderpad + +# Test with system tray mode +./thunderpad --tray + +# Test with specific layout +./thunderpad "layout-name" + +# Update device list in running instance +./thunderpad --update + +# Test accessibility with screen reader +# Start Orca first, then launch thunderpad +``` + +### Accessibility Testing Requirements +**Before any code changes are considered complete:** + +1. **Keyboard Navigation Test**: + - Tab through entire interface without mouse + - Verify all controls are reachable via keyboard + - Test arrow key navigation within lists and tabs + - Ensure Escape key behavior is consistent + +2. **Screen Reader Test**: + - Launch with Orca running + - Verify all interface elements are announced properly + - Check that focus changes are announced + - Ensure list items have descriptive labels + +3. **Focus Management Test**: + - Verify logical tab order (top to bottom, left to right) + - Check that focus is visible (highlight indicators) + - Test that dialogs return focus appropriately when closed + +### Configuration Files and Compatibility +- **ThunderPad layouts**: `~/.config/thunderpad/*.lyt` +- **Last used layout**: `~/.config/thunderpad/layout` +- **Layout compatibility**: Same `.lyt` format as QJoyPad - files can be manually copied between directories +- **Coexistence**: ThunderPad and QJoyPad can run simultaneously (different config dirs, different PID files) + +### Device Detection +- Scans `/dev/input/js*` by default +- Uses libudev for automatic device hotplug detection when available +- Supports manual device directory specification via `--device` flag + +## Interface Changes from QJoyPad + +### Major Accessibility Improvements +1. **Tab-based interface**: Replaced `FlashRadioArray` with `QTabWidget` +2. **List-based controls**: Axes and buttons shown in `QListWidget` instead of clickable grid +3. **Configure buttons**: Dedicated buttons for each control type instead of click-only interfaces +4. **Window mode default**: No system tray dependency for basic operation +5. **Keyboard-only operation**: Every function accessible via keyboard + +### Removed Features (For Accessibility) +- **Translation system**: English-only interface reduces complexity +- **FlashRadioArray widgets**: Replaced with standard Qt accessible widgets +- **Click-to-configure interfaces**: Replaced with explicit configure buttons +- **System tray requirement**: Optional with `--tray` flag + +### Command Line Interface +```bash +thunderpad [OPTIONS] [LAYOUT_NAME] + +Options: + -h, --help Show help message + -d, --device=PATH Specify joystick device directory + -t, --tray Use system tray icon (accessibility: not recommended) + -T, --notray Use window mode (default, accessibility: recommended) + -u, --update Update device list in running instance +``` + +## Code Quality Standards + +### Accessibility Requirements +- **All interactive elements** must be keyboard accessible +- **Proper widget labeling** for screen readers +- **Logical tab order** with explicit `setTabOrder()` when needed +- **Focus indicators** must be visible and announced +- **No mouse-only functionality** - everything must work with keyboard alone + +### Code Style +- **No comments unless necessary** - Keep code self-documenting +- **Follow existing Qt patterns** - Use existing signal/slot architecture +- **Maintain security** - Never log or expose secrets/keys +- **Consistent naming** - Use THUNDERPAD_ prefix for all new macros + +### File Organization +``` +src/ +├── config.h.in # Build-time configuration (THUNDERPAD_* macros) +├── main.cpp # Application entry point +├── layout.h/cpp # Central layout management +├── layout_edit.h/cpp # Main configuration dialog +├── joypad.h/cpp # Individual joystick representation +├── joypadw.h/cpp # Accessible joystick widget +├── button.h/cpp # Button configuration +├── buttonw.h/cpp # Accessible button widget +├── axis.h/cpp # Axis configuration +├── axisw.h/cpp # Accessible axis widget +├── event.h/cpp # X11 event generation +├── error.h # Error handling utilities +└── ... +``` + +## Recent Major Changes + +### Complete Rebranding (QJoyPad → ThunderPad) +- **Project name**: qjoypad → thunderpad +- **Version**: Updated to 2025.06.30 +- **All source files**: Updated header guards, macros, comments +- **Configuration**: New directory `~/.config/thunderpad/` +- **Desktop entry**: New `thunderpad.desktop` file +- **Build system**: CMakeLists.txt updated for new project name + +### Accessibility Transformation +- **Interface redesign**: Complete overhaul for keyboard navigation +- **Widget replacement**: Accessible alternatives to custom widgets +- **Default behavior**: Window mode instead of system tray +- **Translation removal**: English-only for screen reader performance +- **Focus management**: Explicit tab order and focus policies + +### Development Impact +- **Building**: Same CMake process, now produces `thunderpad` executable +- **Testing**: Must include accessibility testing with screen reader +- **Configuration**: New config directory allows coexistence with QJoyPad +- **Installation**: Desktop entry and icons updated for ThunderPad branding + +## Future Development Guidelines + +### Accessibility-First Development +1. **Before implementing any UI change**: + - Consider keyboard navigation impact + - Test with screen reader if possible + - Prefer standard Qt widgets over custom implementations + - Ensure all functionality works without mouse + +2. **Widget selection priority**: + - QListWidget > clickable grids + - QPushButton > mouse-only interactions + - QTabWidget > custom tab implementations + - Standard Qt dialogs > custom dialogs + +3. **Testing requirements**: + - Manual keyboard navigation test + - Screen reader compatibility verification + - Focus flow validation + - No mouse required for any operation + +### Compatibility Considerations +- Maintain `.lyt` file format compatibility with QJoyPad +- Keep command-line interface consistent where possible +- Preserve core joystick mapping functionality +- Ensure coexistence capability with QJoyPad installations + +Remember: **Accessibility is not optional** - it's the core mission of ThunderPad. \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 9c0d1cf..fcaf1a5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,13 +1,12 @@ -cmake_minimum_required(VERSION 2.8.11) +cmake_minimum_required(VERSION 3.5) -project(qjoypad) +project(thunderpad) -set(QJOYPAD_MAJOR 4) -set(QJOYPAD_MINOR 3) -set(QJOYPAD_PATCH 0) +set(THUNDERPAD_MAJOR 2025) +set(THUNDERPAD_MINOR 06) +set(THUNDERPAD_PATCH 30) find_package(Qt5Widgets REQUIRED) -find_package(Qt5LinguistTools REQUIRED) find_package(Qt5X11Extras REQUIRED) option(WITH_LIBUDEV "Use libudev for automatically updating joypad devices." ON) @@ -25,12 +24,10 @@ if(WITH_LIBUDEV) include_directories(${LIBUDEV_INCLUDE_DIRS}) endif() -set(DEVICE_DIR "/dev/input" CACHE PATH "Set the path where QJoyPad will look for your joystick devices. If your devices are /dev/js0, /dev/js1, etc., this should be just \"/dev\". By default, this is /dev/input.") +set(DEVICE_DIR "/dev/input" CACHE PATH "Set the path where ThunderPad will look for your joystick devices. If your devices are /dev/js0, /dev/js1, etc., this should be just \"/dev\". By default, this is /dev/input.") -option(PLAIN_KEYS "Force QJoyPad to use standard XWindows keynames without filtering them for appearance. This will make displays less attractive and readable, but will save processor power and ensure that you see the right names for keys you press." OFF) +option(PLAIN_KEYS "Force ThunderPad to use standard XWindows keynames without filtering them for appearance. This will make displays less attractive and readable, but will save processor power and ensure that you see the right names for keys you press." OFF) -option(UPDATE_TRANSLATIONS "Update source translation locale/*.ts -files (WARNING: make clean will delete the source .ts files! Danger!)") message(STATUS "Using device directory: ${DEVICE_DIR}") @@ -49,23 +46,11 @@ set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -D_DEBUG") # for config.h include_directories("${PROJECT_BINARY_DIR}/src") -file(GLOB qjoypad_TRANS_SOURCES translations/qjoypad*.ts) - -if(UPDATE_TRANSLATIONS) - file(GLOB_RECURSE qjoypad_TRANS_FILES *.cpp *.h) - qt5_create_translation(qjoypad_TRANS ${qjoypad_TRANS_SOURCES} ${qjoypad_TRANS_FILES}) -else() - qt5_add_translation(qjoypad_TRANS ${qjoypad_TRANS_SOURCES}) -endif() add_subdirectory(icons) add_subdirectory(src) -add_custom_target(translations_target DEPENDS ${qjoypad_TRANS}) -add_dependencies(qjoypad translations_target) - -install(PROGRAMS qjoypad.desktop DESTINATION "share/applications") -install(FILES ${qjoypad_TRANS} DESTINATION "share/qjoypad/translations") +install(PROGRAMS thunderpad.desktop DESTINATION "share/applications") # uninstall target configure_file( diff --git a/README.md b/README.md index 83e0494..ee69954 100644 --- a/README.md +++ b/README.md @@ -1,572 +1,380 @@ -QJoyPad 4 -========= +ThunderPad +========== -This is a fork of [QJoyPad](http://qjoypad.sourceforge.net/) with some small additional -features, Qt 5 port and some bug/memory leak fixes. QJoyPad was originally developed by -Nathan Gaylinn and John Toman . -This fork is maintained by Mathias Panzenböck . +**An Accessible Joypad to Keyboard/Mouse Mapper** -![Screenshot](http://i.imgur.com/Cuql4Mr.png) +ThunderPad is an accessibility-focused fork of [QJoyPad](https://github.com/panzi/qjoypad) that provides full screen reader compatibility and keyboard navigation support. Originally developed by Nathan Gaylinn and John Toman, QJoyPad was later maintained by Mathias Panzenböck. This fork, ThunderPad, is developed for the [Stormux](https://stormux.org) project with a focus on making joystick/gamepad configuration fully accessible to users of screen readers like Orca. + +![ThunderPad Configuration Window](http://i.imgur.com/Cuql4Mr.png) Quick Installation ------------------ - git clone https://github.com/panzi/qjoypad - mkdir qjoypad/build - cd qjoypad/build + git clone https://github.com/stormux-dev/thunderpad + mkdir thunderpad/build + cd thunderpad/build cmake .. -DCMAKE_INSTALL_PREFIX=/usr -DCMAKE_BUILD_TYPE=Release make -j`nproc` make install For more details see [Installation](#installation). +## What's New in ThunderPad + +### Accessibility Features +- **Full keyboard navigation**: All interface elements are accessible via Tab/Shift+Tab +- **Screen reader compatible**: Works seamlessly with Orca and other screen readers +- **Accessible list widgets**: Axes and buttons are presented in navigable lists with descriptive labels +- **Clear focus indicators**: Visual and screen reader feedback for current focus position +- **Logical tab order**: Interface elements follow a predictable navigation sequence + +### Interface Changes +- **Tab-based layout**: Replaced clickable interface with keyboard-navigable tabs for each joystick +- **Configure buttons**: Each axis and button has a dedicated configure button accessible via keyboard +- **No tray icon by default**: Opens configuration window directly for better accessibility (use `--tray` to enable system tray) +- **Window mode default**: Runs in window mode by default instead of system tray mode + +### Compatibility +- **Runs alongside QJoyPad**: ThunderPad uses `~/.config/thunderpad/` for settings, allowing coexistence +- **Layout compatibility**: Can manually copy `.lyt` files between QJoyPad and ThunderPad directories +- **Translation removal**: English-only interface reduces complexity and improves screen reader performance + Documentation ------------- ### Introduction -#### What is QJoyPad +#### What is ThunderPad -QJoyPad is a convenient little program with a Qt interface -that converts movement and button presses on a gamepad or -joystick into key presses, mouse clicks, and mouse movement in -XWindows. It should work on almost every Linux system and with -any Linux-supported gaming device. +ThunderPad is an accessible joystick/gamepad configuration tool with a Qt interface that converts movement and button presses on a gamepad or joystick into key presses, mouse clicks, and mouse movement in XWindows. It provides the same functionality as QJoyPad but with a completely redesigned interface optimized for screen reader users and keyboard navigation. #### What's it good for? -QJoyPad lets you play any XWindows game that uses input from -the keyboard and mouse with a joystick device, even if the -game doesn't normally have joystick support. In addition, it's -a convenient companion for emulation software as it prevents -the need for extra controller plugins and can remember -multiple saved layouts. Also, QJoyPad can quickly swap between -layouts whenever you change games, so you'll always have the -controls right where you want them instead of compromising for -the game's defaults or the settings you find most useful in -other games. Now with version 3, QJoyPad also supports -features like rapid fire and sticky buttons (see Section -3.5.2) that can improve your gaming experience. - -Not a gamer? Then QJoyPad can still be pretty useful if you -would find it more comfortable or convenient to control your -computer with a joystick or game pad. It may be designed with -gaming in mind, but it's a useful program for virtually any -purpose. +ThunderPad lets you play any XWindows game that uses input from the keyboard and mouse with a joystick device, even if the game doesn't normally have joystick support. It's particularly valuable for users who rely on screen readers, as the interface is fully accessible and can be operated entirely via keyboard navigation. +In addition to gaming, ThunderPad is useful for anyone who would find it more comfortable or convenient to control their computer with a joystick or game pad, especially users with mobility impairments who may find traditional keyboard/mouse input challenging. #### Features +- **Fully accessible interface** compatible with screen readers like Orca +- **Complete keyboard navigation** - no mouse required for configuration +- **Tab-based interface** for easy navigation between joysticks - Incorporates your gaming devices into any XWindows program - Move and click the mouse with your joystick -- Auto-detects how many joysticks you have and how many - buttons and axes each supports +- Auto-detects how many joysticks you have and how many buttons and axes each supports - Can detect joystick devices on the fly without restarting - Support for devices with more than two axes -- Save as many layouts as you want and switch between them - quickly -- Swap layouts on the fly from the command line or from a - script -- Share layout files with your friends or even edit them by - hand for greater control -- Color cues quickly show you which buttons you're pressing - and which joystick you're using +- Save as many layouts as you want and switch between them quickly +- Swap layouts on the fly from the command line or from a script +- Share layout files with your friends or even edit them by hand for greater control - Set or reset all the keys at once in a flash - Adjust the sensitivity of every axis independently -- Quietly hides in your system tray, running in the - background without taking up space -- For window managers without a system tray, QJoyPad can run - without the tray icon. -- Make an axis "Gradient" so that a light push does a little - and a harder push does more +- **Window mode by default** - no system tray dependency for accessibility +- Optional system tray mode available with `--tray` flag +- Make an axis "Gradient" so that a light push does a little and a harder push does more - Support for throttle controls -- Make a button "Sticky" if you don't feel like holding it - down all the time +- Make a button "Sticky" if you don't feel like holding it down all the time - Turn on Rapid Fire so you don't wear out your gamepad! -- If libudev is availabe the joypad list will automatically - udpated. - +- If libudev is available, the joypad list will automatically update ### Getting Started #### Requirements - A Linux computer and a Linux-compatible gaming device -- A Linux kernel with joystick support (see the [Linux - Kernel](https://www.kernel.org/) and the Linux joystick driver documentation - [joystick.txt](https://www.kernel.org/doc/Documentation/input/joystick.txt) and - [joystick-parport.txt](https://www.kernel.org/doc/Documentation/input/joystick-parport.txt)) +- A Linux kernel with joystick support (see the [Linux Kernel](https://www.kernel.org/) and the Linux joystick driver documentation [joystick.txt](https://www.kernel.org/doc/Documentation/input/joystick.txt) and [joystick-parport.txt](https://www.kernel.org/doc/Documentation/input/joystick-parport.txt)) - [XWindows](http://x.org/) - [Qt 5](http://qt-project.org/) - [libudev](http://www.freedesktop.org/software/systemd/libudev/) (optional) - +- For full accessibility: A screen reader like [Orca](https://wiki.gnome.org/Projects/Orca) #### Installation -Installing QJoyPad should be a quick and painless process. The -basic procedure is: +Installing ThunderPad should be a quick and painless process. The basic procedure is: - git clone https://github.com/panzi/qjoypad - mkdir qjoypad/build - cd qjoypad/build + git clone https://github.com/stormux-dev/thunderpad + mkdir thunderpad/build + cd thunderpad/build cmake .. -DCMAKE_BUILD_TYPE=Release make -j`nproc` make install -However, there are some settings that might need to be -changed. +However, there are some settings that might need to be changed. -1. Device directory: By default, QJoyPad will look for - joystick devices in `/dev/input`, but if your system puts - them somewhere else, you'll need to run cmake like this: +1. Device directory: By default, ThunderPad will look for joystick devices in `/dev/input`, but if your system puts them somewhere else, you'll need to run cmake like this: `cmake .. -DDEVICE_DIR=/dev` - Do this if your joystick devices are `/dev/js0`, `/dev/js1` - etc. + Do this if your joystick devices are `/dev/js0`, `/dev/js1` etc. -2. Install prefix: The default install prefix is `/usr`. To - change this invoke cmake like this: +2. Install prefix: The default install prefix is `/usr`. To change this invoke cmake like this: `cmake .. -DCMAKE_INSTALL_PREFIX=/usr` -3. Use Plain Keys: Normally, QJoyPad doesn't use standard - XWindows key names to describe your keyboard, but instead - uses names that look nicer and are easier to recognize. - For instance, instead of "KP\_Begin", "Prior", and - "Shift\_L", QJoyPad uses "KP 5", "PageDown", and "L Shift". - If you would rather like the original X11 key names you can - invoke cmake like this: +3. Use Plain Keys: Normally, ThunderPad doesn't use standard XWindows key names to describe your keyboard, but instead uses names that look nicer and are easier to recognize. For instance, instead of "KP\_Begin", "Prior", and "Shift\_L", ThunderPad uses "KP 5", "PageDown", and "L Shift". If you would rather like the original X11 key names you can invoke cmake like this: `cmake .. -DPLAIN_KEYS=ON` -4. Disable libudev support: If you don't have libudev you can - disable libudev support like this: +4. Disable libudev support: If you don't have libudev you can disable libudev support like this: `cmake .. -DWITH_LIBUDEV=OFF` +### Using ThunderPad -### Using QJoyPad +#### Default Window Mode -#### The Tray Icon +Unlike QJoyPad, ThunderPad runs in window mode by default for better accessibility. When you start ThunderPad, it will automatically open the configuration window where you can set up your joystick mappings using full keyboard navigation. -![Tray Icon and Popup Menu](http://i.imgur.com/8kc0CQ6.png) +#### Accessible Interface Navigation -QJoyPad is centered around the idea of a "tray icon", a -little icon that usually sits on your taskbar, out of the way; -when you first run QJoyPad, this is how it will be, just an -icon. If your window manager doesn't support system tray -icons, then you'll see QJoyPad as a tiny 24x24 window floating -around like any other window (see [But my window manager -doesn't HAVE a system tray!](#but-my-window-manager-doesnt-have-a-system-tray)). -since this might be hard to work with, QJoyPad (starting with -version 3.3) gives you the option of having a larger icon to -work with; just run qjoypad --notray and QJoyPad will use a -larger floating icon instead of a system tray icon. +ThunderPad's interface is designed for keyboard navigation: -By right clicking on the QJoyPad icon (it should look like an -old gamepad), you will get a pop-up menu that lets you switch -layouts (when you first install QJoyPad, there will be no -layouts available) and see some important information. To add -or modify layouts, left click the icon to open the Setup -Dialog. +- **Tab/Shift+Tab**: Navigate between interface elements +- **Enter/Space**: Activate buttons and open configuration dialogs +- **Arrow keys**: Navigate within lists and tabs +- **Esc**: Close dialogs and return to main interface -#### The Popup Menu +#### The Configuration Window -When you right click the QJoyPad icon, a menu should pop up. -The top of this menu shows you which joystick devices are -currently available (see [Joystick recognition](#joystick-recognition) -if not all your devices are listed). Below that are the options -to update the layout list or the joystick devices; use these if -you have just put a new layout in ~/.config/qjoypad4 by hand or if -you've plugged in a new joystick device. Below even farther is -a list of the available layouts and the option to quit. +The main configuration window contains: -#### The Setup Dialog +##### Layout Management Section +At the top are controls for managing your controller layouts: +- **Layout dropdown**: Select from saved layouts +- **Add button**: Create a new layout +- **Remove button**: Delete the current layout +- **Rename button**: Rename the current layout +- **Import/Export buttons**: Share layouts with others +- **Save/Revert buttons**: Save changes or restore from file -![Setup Dialog](http://i.imgur.com/f3TxINW.png) +##### Joystick Tabs +Each connected joystick appears as a separate tab. Use Ctrl+Tab or click to switch between joysticks. -The following sections describe the parts of the Setup Dialog -going from the top down and from left to right. +##### Axes and Buttons Lists +Within each joystick tab: +- **Axes list**: Shows all joystick axes with their current assignments +- **Configure Axis button**: Opens configuration for the selected axis +- **Buttons list**: Shows all joystick buttons with their current assignments +- **Configure Button button**: Opens configuration for the selected button +- **Clear/Quick Set buttons**: Reset all assignments or use quick configuration mode -##### The Layout Selection combo box +#### System Tray Mode (Optional) -At the top of the Setup Dialog is a combo box that says [NO -LAYOUT] to begin with, but as you add new layouts it will -serve as a drop-down list of all the layouts available to you. +If you prefer the traditional tray icon interface, you can use: -##### The Add button + thunderpad --tray -The Add button adds a new layout to the list, asking you for a -meaningful name. Make the name short, simple, and easy to -remember, just in case you ever want to load the new layout -from the command line. You can use any name you like that -would be a legal filename on your computer (see [Layout -Files](#layout_files) for details). +This will minimize ThunderPad to the system tray. Right-click the tray icon to access layouts and settings. -#### The Remove button +#### Quick Set Feature -The Remove button deletes the layout currently selected in the -combo box, losing it forever. +The Quick Set feature provides rapid configuration: +1. Click the "Quick Set" button +2. Press any button or move any axis on your controller +3. ThunderPad will prompt you to assign a keyboard key or mouse action +4. Repeat for all controls you want to configure +5. Click "Done" when finished -#### The Save button +### Command-line use and scripting -The Save button saves how the keys are currently set to the -current layout. Use this to make changes to an already-defined -layout. Don't forget to use Save to save any changes you -make before quitting or switching to another layout, or all -the changes will be forgotten! +ThunderPad supports the same command-line interface as QJoyPad for loading layouts: -#### The Revert button + thunderpad "Tetris" -The Revert button does about the opposite of Save. If you've -gone and changed the keys around, pressing Revert will return -them to how they are saved in the current layout. +If ThunderPad isn't running, it will start and load the "Tetris" layout. If it's already running, it will switch to that layout. -#### The Joystick buttons +You can create shell scripts to automatically load appropriate layouts when starting games: -Immediately below the Add, Remove, Save, and Revert buttons, -there are several buttons labeled like "Joystick 1 (Microsoft -X-Box 360 pad)", "Joystick 2 (Nintendo Wiimote)", etc. that -serve as tabs so you can switch between different controllers -to set keys. Whichever one of these buttons is pressed is the -controller you are currently editing. Pressing any button or -moving any axis on a given controller will make its associated -button flash to let you know which it is. + #!/bin/sh + + thunderpad "XGalaga" & + xgalaga++ -#### The Joystick Component buttons +## Layout Files and Compatibility -Beneath the Joystick Buttons is a large pile of buttons -representing every axis and button on your controller. -Whenever you move the axis or push the button that one of -these buttons represents, it will flash blue so that you know -which it is. To setup any of these, just click on the -appropriate button and a dialog will pop up to let you choose -your settings. +### ThunderPad Layout Directory -#### The Clear button +ThunderPad stores its configuration files in `~/.config/thunderpad/`, separate from QJoyPad's `~/.config/qjoypad4/` directory. This allows both programs to coexist without conflicts. -The Clear button resets all the axes and buttons to nothing, -essentially rendering the joystick disabled. From here it's -easy enough to set the buttons you need, starting from a clean -slate. +### Sharing Layouts with QJoyPad -#### Quick Set +ThunderPad uses the same `.lyt` file format as QJoyPad, so layouts can be shared: -The Quick Set button does exactly what you'd expect, it lets -you set all the buttons and axes quickly! When you click it, -it brings up a little window with a Done button, and until you -click Done it's watching the controller. Whenever you press a -button or move an axis, it will ask you which button you want -associated with that movement. You can't set all the extra -options this way, but it's much faster than going through all -the dialogs! +1. **From QJoyPad to ThunderPad**: Copy `.lyt` files from `~/.config/qjoypad4/` to `~/.config/thunderpad/` +2. **From ThunderPad to QJoyPad**: Copy `.lyt` files from `~/.config/thunderpad/` to `~/.config/qjoypad4/` + +After copying files, restart the application or use the "Update Layout List" option to see the new layouts. + +### Layout File Format + +Layout files use standard X11 keycodes and are human-readable. You can edit them manually if needed. The format includes: +- Joystick definitions with axis and button mappings +- Key assignments using X11 keycodes +- Mouse movement and click assignments +- Special properties like rapid fire and sticky buttons + +## Differences from QJoyPad + +### Accessibility Improvements +- **Complete keyboard navigation**: No mouse required for any configuration task +- **Screen reader support**: All interface elements have proper labels and descriptions +- **Focus management**: Clear visual and audio feedback for current focus position +- **Simplified interface**: Removed complex clickable widgets in favor of accessible lists and buttons + +### Interface Changes +- **Tab-based layout**: Replaced Flash widget arrays with standard Qt tab widgets +- **List-based controls**: Axes and buttons presented in navigable lists rather than clickable grids +- **Default window mode**: No system tray icon by default (use `--tray` to enable) +- **Dedicated configure buttons**: Each control has its own configuration button for keyboard access + +### Behavioral Changes +- **No translation system**: English-only interface reduces complexity and improves screen reader performance +- **Separate config directory**: Uses `~/.config/thunderpad/` to avoid conflicts with QJoyPad +- **Direct window opening**: Shows configuration window immediately instead of hiding in system tray + +## Command Line Options + + thunderpad [OPTIONS] [LAYOUT_NAME] + +**Options:** +- `-h, --help`: Show help message +- `-d, --device=PATH`: Specify joystick device directory (default: `/dev/input`) +- `-t, --tray`: Use system tray icon (instead of default window mode) +- `-T, --notray`: Use window mode (default behavior) +- `-u, --update`: Update device list in running instance + +**Layout Name:** Load the specified layout on startup + +## Troubleshooting + +### Accessibility Issues + +#### Screen reader not announcing interface elements +- Ensure you're using a recent version of Orca or your preferred screen reader +- Try restarting your screen reader after launching ThunderPad +- Check that Qt accessibility is enabled in your desktop environment + +#### Tab navigation not working as expected +- Use Tab/Shift+Tab to move between major interface elements +- Use arrow keys within lists and combo boxes +- If focus seems stuck, try pressing Escape to return to the main interface + +### General Issues + +Most troubleshooting steps from QJoyPad apply to ThunderPad. See the original documentation sections below for: +- Joystick recognition problems +- Device detection issues +- Sensitivity and calibration problems + +### Running Alongside QJoyPad + +ThunderPad and QJoyPad can run simultaneously since they use different configuration directories and process names. However, both will attempt to access the same joystick devices, which may cause conflicts. It's recommended to use only one at a time. + +## Credits + +ThunderPad is based on [QJoyPad](https://github.com/panzi/qjoypad), originally developed by Nathan Gaylinn and John Toman , with Qt 5 port and additional features by Mathias Panzenböck . + +Accessibility improvements and ThunderPad fork developed for the [Stormux](https://stormux.org) project. + +Special thanks to the screen reader and accessibility communities for feedback and testing. + +## Original QJoyPad Documentation + +The following sections contain the original QJoyPad documentation, which remains relevant for ThunderPad's core functionality: + +--- ### Configuring axes ![Axis Edit](http://i.imgur.com/CPcyuq2.png) -In QJoyPad 2, you were allowed one key to be assigned to each -of four directions, Up, Down, Left, and Right. In version 3, -there is support for many axes and each one can do fancier -things than just press a key. Unfortunately, since different -controllers do things differently, it's not as easy as Up, -Down, Left, and Right. Up-Down is an axis, Left-Right is an -axis, and if you have a nicer controller, you might have many -more axes on top of that. +In QJoyPad 2, you were allowed one key to be assigned to each of four directions, Up, Down, Left, and Right. In version 3, there is support for many axes and each one can do fancier things than just press a key. Unfortunately, since different controllers do things differently, it's not as easy as Up, Down, Left, and Right. Up-Down is an axis, Left-Right is an axis, and if you have a nicer controller, you might have many more axes on top of that. -The first step in configuring axes is to figure out which one -you want to set. If you have a joystick, try moving it around -and seeing which buttons flash blue on the QJoyPad Setup -Dialog. If you have a gamepad, try pressing different buttons -on the Directional-Pad or moving around any mini joystick -controls it might have. Once you know which axis you want to -set, click on its associated button to open the Set Axis -dialog. +The first step in configuring axes is to figure out which one you want to set. If you have a joystick, try moving it around and seeing which items are highlighted in the axes list. If you have a gamepad, try pressing different buttons on the Directional-Pad or moving around any mini joystick controls it might have. Once you know which axis you want to set, select it in the list and click the "Configure Axis" button. #### The Axis Position Indicator -In the middle of this dialog, you will see a white bar, -divided in two, that represents the current position of the -axis you're editing. Try moving that axis to see how it works. -This is so you know which direction is considered "positive" -and which is "negative"; it might not be what you'd expect. If -this axis is a D-Pad, then it is either off or on, but most -other axes are sensitive to how far they are depressed and a -colored bar here will show you how far it is at the moment. +In the middle of this dialog, you will see a white bar, divided in two, that represents the current position of the axis you're editing. Try moving that axis to see how it works. This is so you know which direction is considered "positive" and which is "negative"; it might not be what you'd expect. If this axis is a D-Pad, then it is either off or on, but most other axes are sensitive to how far they are depressed and a colored bar here will show you how far it is at the moment. -Along the white bar, you will also see small blue and red tabs -that you can drag. These adjust the "Dead Zone" and the -"Extreme Zone" of the axis. When the colored bar representing -the axis' position passes one of the blue markers, the bar -will turn blue meaning that when the axis is this far QJoyPad -will consider it moved, and when the bar passes one of the red -markers it will turn red and QJoyPad will consider that axis -fully depressed. When the bar is gray, that means that you -haven't moved the axis out of its Dead Zone and QJoyPad is -ignoring its movement. To adjust where the Dead and Extreme -Zones are, just slide the blue and red markers to where you -think they should be. +Along the white bar, you will also see small blue and red tabs that you can drag. These adjust the "Dead Zone" and the "Extreme Zone" of the axis. When the colored bar representing the axis' position passes one of the blue markers, the bar will turn blue meaning that when the axis is this far QJoyPad will consider it moved, and when the bar passes one of the red markers it will turn red and QJoyPad will consider that axis fully depressed. When the bar is gray, that means that you haven't moved the axis out of its Dead Zone and QJoyPad is ignoring its movement. To adjust where the Dead and Extreme Zones are, just slide the blue and red markers to where you think they should be. -You probably won't need to adjust the sensitivity unless you -are having trouble getting QJoyPad to generate key presses -when you want it to (see [Joystick adjustment](#joystick-adjustment)). +You probably won't need to adjust the sensitivity unless you are having trouble getting QJoyPad to generate key presses when you want it to (see [Joystick adjustment](#joystick-adjustment)). #### Set an axis to 0-max, relative (gradient), or absolute movement -On the upper half of the dialog, you will see another drop-down -set to relative movement. In 0-max mode QJoyPad generates just one -key press when the axis is moved. In case of relative and absolute -QJoyPad will start flickering that key on and off as soon as the -axis is out of the Dead Zone (when the colored bar turns blue). How -far the axis is pushed determines what percent of the time the -simulated key will be depressed. As soon as the axis enters -its Extreme Zone (when the colored bar turns red), the key -will be down 100% of the time. Setting an axis to relative is -useful if you want to use it as an accelerator in a game so -how fast you go is controlled by how far the axis is moved. -Also, it's nice to use this when the axis is set to move the -mouse because it can give you finer control of the mouse when -you push the axis just a little but still let you move quickly -when you push it all the way. +On the upper half of the dialog, you will see another drop-down set to relative movement. In 0-max mode QJoyPad generates just one key press when the axis is moved. In case of relative and absolute QJoyPad will start flickering that key on and off as soon as the axis is out of the Dead Zone (when the colored bar turns blue). How far the axis is pushed determines what percent of the time the simulated key will be depressed. As soon as the axis enters its Extreme Zone (when the colored bar turns red), the key will be down 100% of the time. Setting an axis to relative is useful if you want to use it as an accelerator in a game so how fast you go is controlled by how far the axis is moved. Also, it's nice to use this when the axis is set to move the mouse because it can give you finer control of the mouse when you push the axis just a little but still let you move quickly when you push it all the way. #### Switching between keyboard and mouse control -On the upper half of the dialog, there is a combo box that -lets you choose between keyboard control and mouse control. -There are four different mouse options that let you choose -whether the mouse will move vertically (Up-Down) when the axis -moves or horizontally (Left-Right). You can also reverse the -direction of the mouse if you want moving the axis up to move -the mouse down or visa versa. +On the upper half of the dialog, there is a combo box that lets you choose between keyboard control and mouse control. There are four different mouse options that let you choose whether the mouse will move vertically (Up-Down) when the axis moves or horizontally (Left-Right). You can also reverse the direction of the mouse if you want moving the axis up to move the mouse down or visa versa. **Tip** -Usually you want an axis to be relative or absolute if it's going -to move the mouse. Relative to pass relative mouse movements, and -absolute to place the mouse on the screen according to the axis -position. +Usually you want an axis to be relative or absolute if it's going to move the mouse. Relative to pass relative mouse movements, and absolute to place the mouse on the screen according to the axis position. #### Adjusting mouse speed -When using one of the mouse modes, you can set the speed of -the mouse by adjusting the number in the upper right corner. +When using one of the mouse modes, you can set the speed of the mouse by adjusting the number in the upper right corner. #### Setting keys -When using keyboard mode, you can set which key corresponds to -which direction of the axis by clicking the buttons -immediately below the Axis Position Indicator. The one on the -left will be pressed when the axis is moved in the negative -direction (when the colored bar is on the left side) and the -one on the right when it is in the positive direction (when -the colored bar is on the right side). +When using keyboard mode, you can set which key corresponds to which direction of the axis by clicking the buttons immediately below the Axis Position Indicator. The one on the left will be pressed when the axis is moved in the negative direction (when the colored bar is on the left side) and the one on the right when it is in the positive direction (when the colored bar is on the right side). #### Throttle Settings -Between these two buttons is another combo box that changes -the throttle settings. This is meant for gamepads which have a -specific type of throttle control. What it does is instead of -having two keys for when the axis is positive or negative, it -has just one and treats the way the axis moves differently. In -one of the throttle modes, the axis will be considered -centered when it is all the way to one direction or the other. +Between these two buttons is another combo box that changes the throttle settings. This is meant for gamepads which have a specific type of throttle control. What it does is instead of having two keys for when the axis is positive or negative, it has just one and treats the way the axis moves differently. In one of the throttle modes, the axis will be considered centered when it is all the way to one direction or the other. ### Configuring buttons -![BUtton Edit](http://i.imgur.com/Grwrunu.png) +![Button Edit](http://i.imgur.com/Grwrunu.png) -Similarly to the buttons corresponding to axes in the Setup -Dialog, the ones corresponding to the buttons on your -controller also light up to let you know which is which. To -figure out which button you want, press it on the game device -and then click on the button on screen that flashed. A small -settings dialog will pop up. +Similarly to the axes, buttons are listed in the buttons list. To configure a button, select it from the list and click "Configure Button". You can also press the physical button on your controller to see which item gets highlighted in the list. #### Choosing a key / mouse button -At the top of this dialog is a button that you can click to -set which key or mouse button you want to associate with this -button on your controller. Just click on it, and the rest -should be self-explanatory. +At the top of this dialog is a button that you can click to set which key or mouse button you want to associate with this button on your controller. Just click on it, and the rest should be self-explanatory. #### Making a button "Sticky" -Below this and to the left is a little checkbox marked Sticky. -When a button is set as Sticky, that means that pressing the -button once will make QJoyPad simulate a key press (or mouse -button press) and pressing that button again will make QJoyPad -release the simulated key. This is useful for racing games -where you're almost always pouring on the gas, or for RPGs -that have a button used for run, even though it's always -better to be running. This way, all you have to do is press -the button once and it's like you're holding it down. To let -the button back up, just press it a second time. +Below this and to the left is a little checkbox marked Sticky. When a button is set as Sticky, that means that pressing the button once will make QJoyPad simulate a key press (or mouse button press) and pressing that button again will make QJoyPad release the simulated key. This is useful for racing games where you're almost always pouring on the gas, or for RPGs that have a button used for run, even though it's always better to be running. This way, all you have to do is press the button once and it's like you're holding it down. To let the button back up, just press it a second time. #### Using Rapid Fire -Just next to the Sticky checkbox is another one marked Rapid -Fire. When this is enabled for a button, holding that button -down means that QJoyPad will flicker the associated key very -fast. This is great for space shooters where you want to fire -quickly but you don't want to break your button (or your -thumb!) from pressing over and over again. +Just next to the Sticky checkbox is another one marked Rapid Fire. When this is enabled for a button, holding that button down means that QJoyPad will flicker the associated key very fast. This is great for space shooters where you want to fire quickly but you don't want to break your button (or your thumb!) from pressing over and over again. **Tip** -Keep in mind that any button can be set both Sticky AND Rapid -Fire. This is even better for space shooters because this way -all you need to do is press the button once and from then -until you press it again you will be shooting Rapid Fire. - -### Command-line use and scripting - -Although QJoyPad only works in XWindows, it supports changing -axes on the fly from the command line. If you want to load up -the layout named "Tetris", all you have to do is run: - - qjoypad "Tetris" - -and one of two things will happen. If QJoyPad isn't currently -open, it will start running and load the "Tetris" layout (this -is case sensitive! see [Layout Files](#layout-files)). If -QJoyPad is already running, it will just silently switch to the -requested layout. - -What's so great about this is it lets you forget about QJoyPad -once you've made all your layouts, and just worry about your -games! It's very easy to write short little shell scripts to -automatically load the layout you need when you start up a -game. For instance, if you wanted to run the game xgalaga++, -using QJoyPad for joystick support, you could create a text -file called run-xgalaga with the following lines in it: - - #!/bin/sh - - qjoypad "XGalaga" & - xgalaga++ - -Then with the command "chmod a+x run-xgalaga" you could make -that text file an executable shell script; once that's done, -all you need to to do is execute run-xgalaga and QJoyPad will -load the appropriate layout and your game will start. To use -this script for any other program, just change "XGalaga" to a -different layout name and "xgalaga++" to the name of some -other program and you're done. - -## Layout Files - -When QJoyPad saves a layout, it creates a file using that -layout's name. Because of this, layout names must also be -valid filenames. This shouldn't be very limiting, it just -means that names can't contain certain special characters such -as '/' and dependig on your file system '\*', etc. Remember -that most Linux file systems are case sensitive, so a layout -named "Layout" will be considered distinct from a layout named -"layout". On most modern file systems, spaces should be okay -and there should be no serious limits on name length. - -Whenever you create a new layout, QJoyPad makes a new file -called Name.lyt in `~/.config/qjoypad4`, where Name is the name that -you provided. Whenever you update that layout, it overwrites -that file to reflect your changes, whenever you revert, it -rereads that file, and if you ever remove that layout, it will -erase that file from your hard drive. - -The format of these files isn't difficult to figure out, so -you can edit them by hand if you like. The numbers used to -represent keys are standard X11 keycodes. - -It's also easy to share QJoyPad layout files; just copy them -from one user's `~/.config/qjoypad4` directory to another and either -tell QJoyPad to update the layout list by right clicking on -the tray icon, or just restart QJoyPad. If you switch layouts -through the command line, you don't even need to do that. +Keep in mind that any button can be set both Sticky AND Rapid Fire. This is even better for space shooters because this way all you need to do is press the button once and from then until you press it again you will be shooting Rapid Fire. ## Problems -### I can't get my game controller to work in Linux; will QJoyPad help? +### I can't get my game controller to work in Linux; will ThunderPad help? -Well, that depends on why you can't get it to work. For the -most part, the answer is "No." QJoyPad can only use joysticks -and gamepads that are recognized by your kernel and that have -the proper drivers loaded. If you can't get your joysticks to -work at all in Linux, then, no, QJoyPad can't help. (you might -want to check out -[joystick.txt](https://www.kernel.org/doc/Documentation/input/joystick.txt) -or [joystick-parport.txt](https://www.kernel.org/doc/Documentation/input/joystick-parport.txt); -if you don't know anything about working with the kernel, -check out the [Linux Kernel HOWTO](http://www.linuxdocs.org/HOWTOs/Kernel-HOWTO.html), -although this document seems to be outdated) +Well, that depends on why you can't get it to work. For the most part, the answer is "No." ThunderPad can only use joysticks and gamepads that are recognized by your kernel and that have the proper drivers loaded. If you can't get your joysticks to work at all in Linux, then, no, ThunderPad can't help. (you might want to check out [joystick.txt](https://www.kernel.org/doc/Documentation/input/joystick.txt) or [joystick-parport.txt](https://www.kernel.org/doc/Documentation/input/joystick-parport.txt); if you don't know anything about working with the kernel, check out the [Linux Kernel HOWTO](http://www.linuxdocs.org/HOWTOs/Kernel-HOWTO.html), although this document seems to be outdated) -If your joystick is detected and somewhat working, but you -can't get it to work in specific programs, then QJoyPad just -might be what you're looking for. One of the main reasons I -wrote QJoyPad was because my (Nathan Gaylinn's) gamepads simply -wouldn't work right with the input plugins for Linux Playstation -emulators, so I know for a fact that sometimes QJoyPad can work -around specific software issues. +If your joystick is detected and somewhat working, but you can't get it to work in specific programs, then ThunderPad just might be what you're looking for. One of the main reasons QJoyPad was originally created was because gamepads simply wouldn't work right with the input plugins for Linux Playstation emulators, so we know for a fact that sometimes ThunderPad can work around specific software issues. -Check out [Joystick recognition](#joystick-recognition) for -some tips for checking if your joystick is working. +Check out [Joystick recognition](#joystick-recognition) for some tips for checking if your joystick is working. ### Joystick recognition -#### QJoyPad says it can't find any joysticks? +#### ThunderPad says it can't find any joysticks? -#### QJoyPad isn't showing all of my joysticks. +#### ThunderPad isn't showing all of my joysticks. #### My joystick has more/fewer buttons/axes than that! -QJoyPad automatically recognizes your joysticks using the -Linux joystick driver, so all joysticks must be working -properly in Linux before they can be used in QJoyPad. If you -can't see all of your joysticks or if QJoyPad complains it -can't find any, chances are your joystick(s) are not plugged -in or are not properly detected by Linux. If that's not it, -QJoyPad could also be looking for your joysticks in the wrong -directory. +ThunderPad automatically recognizes your joysticks using the Linux joystick driver, so all joysticks must be working properly in Linux before they can be used in ThunderPad. If you can't see all of your joysticks or if ThunderPad complains it can't find any, chances are your joystick(s) are not plugged in or are not properly detected by Linux. If that's not it, ThunderPad could also be looking for your joysticks in the wrong directory. -First, double check that your joysticks are plugged in. If -they aren't, plug them, load any modules you might need, and -tell QJoyPad to Update joystick devices with the popup menu -(remember, this menu is only accessible when the Setup Dialog -is closed). +First, double check that your joysticks are plugged in. If they aren't, plug them, load any modules you might need, and tell ThunderPad to Update joystick devices with the popup menu (if using tray mode) or restart ThunderPad. -If you're still having trouble, QJoyPad might have been -compiled with the devdir setting pointing to the wrong place. -That option had to be set at compile time, and to change it -you must recompile (see [Installation](#installation)); however, -if you don't want to bother with that, you can specify the -location of your devices as an argument. Using the command -`qjoypad --device /dev/input`, for example, will start QJoyPad -and tell it to look for joysticks in `/dev/input/js0`, -`/dev/input/js1`, etc. +If you're still having trouble, ThunderPad might have been compiled with the devdir setting pointing to the wrong place. That option had to be set at compile time, and to change it you must recompile (see [Installation](#installation)); however, if you don't want to bother with that, you can specify the location of your devices as an argument. Using the command `thunderpad --device /dev/input`, for example, will start ThunderPad and tell it to look for joysticks in `/dev/input/js0`, `/dev/input/js1`, etc. -If that doesn't work, then you might want to make sure your -joysticks are working properly. One way to test this is to do -a `cat /dev/input/js0` (or wherever your joystick device is) -and press a few buttons on the controller. If you get a bunch -of crazy characters, it's working. If not, you'll have to -fiddle around with kernel drivers, and should probably look -elsewhere for guidance. Or you can install the jstest command -line tool and use `jstest /dev/input/js0`, which will give you -a much nicer output. +If that doesn't work, then you might want to make sure your joysticks are working properly. One way to test this is to do a `cat /dev/input/js0` (or wherever your joystick device is) and press a few buttons on the controller. If you get a bunch of crazy characters, it's working. If not, you'll have to fiddle around with kernel drivers, and should probably look elsewhere for guidance. Or you can install the jstest command line tool and use `jstest /dev/input/js0`, which will give you a much nicer output. -If for some reason QJoyPad is reporting the wrong number of -buttons or axes for your device, that means the Linux joystick -driver is also reporting the wrong number. Unless you can't -get to buttons or axes that you need, this shouldn't be a -problem, but if you want to get the number right, Try using a -different driver or check out the documentation for the one -you're using. +If for some reason ThunderPad is reporting the wrong number of buttons or axes for your device, that means the Linux joystick driver is also reporting the wrong number. Unless you can't get to buttons or axes that you need, this shouldn't be a problem, but if you want to get the number right, Try using a different driver or check out the documentation for the one you're using. -If your joysticks are working, plugged in, and QJoyPad is -looking in the right place, then I'm not sure what to tell -you. Unfortunately, I don't have a wealth of different devices -and software setups to test on. If you're really stuck and think -it's QJoyPad's fault please [write a bug -report](https://github.com/panzi/qjoypad/issues). +If your joysticks are working, plugged in, and ThunderPad is looking in the right place, then I'm not sure what to tell you. Unfortunately, we don't have a wealth of different devices and software setups to test on. If you're really stuck and think it's ThunderPad's fault please [write a bug report](https://github.com/stormux-dev/thunderpad/issues). ### Joystick adjustment @@ -576,233 +384,30 @@ report](https://github.com/panzi/qjoypad/issues). #### I'm pushing up, but nothing's happening! -Chances are, this means you're using an overly sensitive or -poorly calibrated joystick or your sensitivity settings are -all wrong. Try adjusting the Dead Zone of the axes that are -giving you trouble (move the blue tab in the Axis Edit -dialog), more away from the center if it thinks you're -pressing a button when you aren't, more toward the center if -it thinks you aren't pressing a button when you are. If that -doesn't work, try manually adjusting your joystick (if it has -adjustment knobs/sliders), or try calibrating it with jscal -or with the KDE system settings "Input Devices" module. +Chances are, this means you're using an overly sensitive or poorly calibrated joystick or your sensitivity settings are all wrong. Try adjusting the Dead Zone of the axes that are giving you trouble (move the blue tab in the Axis Edit dialog), more away from the center if it thinks you're pressing a button when you aren't, more toward the center if it thinks you aren't pressing a button when you are. If that doesn't work, try manually adjusting your joystick (if it has adjustment knobs/sliders), or try calibrating it with jscal or with the KDE system settings "Input Devices" module. -### QJoyPad won't start! +### ThunderPad won't start! -There are two reasons why QJoyPad won't start. For one, -QJoyPad won't start is if it's already running! To make sure -QJoyPad doesn't interfere with itself, only one version of -QJoyPad is allowed to run at a time. If you can't see an -already open version, look for the icon in the system tray. If -you really can't find it anywhere, try running `killall qjoypad` -and then `rm -f /tmp/qjoypad.pid` and then try starting -QJoyPad again. It should work this time. +There are two reasons why ThunderPad won't start. For one, ThunderPad won't start is if it's already running! To make sure ThunderPad doesn't interfere with itself, only one version of ThunderPad is allowed to run at a time. If you can't see an already open version, look for the icon in the system tray (if using `--tray` mode). If you really can't find it anywhere, try running `killall thunderpad` and then `rm -f /tmp/thunderpad.pid` and then try starting ThunderPad again. It should work this time. -Finally, QJoyPad won't actually run if one of its arguments is -`-h` or `--help`. When it sees one of those arguments, it outputs -usage information to the console and then quits. If you're -running QJoyPad away from a console or want it to run like -normal, don't give one of these arguments. +Finally, ThunderPad won't actually run if one of its arguments is `-h` or `--help`. When it sees one of those arguments, it outputs usage information to the console and then quits. If you're running ThunderPad away from a console or want it to run like normal, don't give one of these arguments. -### I have two versions of QJoyPad open at once and they're getting in each other's way! +### I have two versions of ThunderPad/QJoyPad open at once and they're getting in each other's way! -QJoyPad doesn't work well when there are two or more instances -open; for that reason, it uses a file to tell whether or not -it's already running. Every version of QJoyPad has done this, -but in version 3.4, where that file is kept was changed to -make the program more compatible with certain distributions. +ThunderPad and QJoyPad use different PID files (`/tmp/thunderpad.pid` vs `/tmp/qjoypad.pid`), so they can run simultaneously. However, both will try to access the same joystick devices, which may cause conflicts. If you experience issues, close one of the applications. -If you're seeing two versions of QJoyPad open at once, that -means that either one of those is QJoyPad 3.4 or newer and the -other is an older version, or that you're running an older -version of QJoyPad on a system where you don't have write access -to `/tmp`. In either case, you should just make sure that you -are running the newest version of QJoyPad and that there are -no other versions installed on your system. - -If you really want to keep earlier versions of QJoyPad, that's -fine! Just remember that if you do, it's possible to have two -instancesrunning at once and that that can cause problems. - -### I'm getting strange errors when I change layouts; what's wrong? - -Those errors show that there is something wrong with the -layout files themselves. This means the files were corrupted, -edited incorrectly, or for some reason QJoyPad didn't save -them right (shouldn't ever happen, never seen it happen, but -nothing's impossible). Unless the file QJoyPad is looking for -is completely missing or mangled, it's quite likely that the -file can be repaired by hand. If you need help with the save -format, just send me an email -and I'll see if I can't help. - -If worse comes to worst and you lose a layout file you -created, it shouldn't take you too long to rebuild it from -scratch. +If you have multiple instances of the same application, make sure you don't have old versions installed alongside newer ones. ### This program only works in XWindows? -Yep, I'm afraid so. For all of you out there with old Linux -console games that won't run in an xterm, you'll have to try -something else. If you really must find a way, -[joy2key](https://sourceforge.net/projects/joy2key/) is a -program that is similar to QJoyPad but without a graphical -interface or many of the fancier features, but which doesn't -have that limitation. Another alternative is -[Jojsticken](http://jojsticken.sourceforge.net/). (See the -links section there to find even more alternatives.) -Finally there is [AntiMicro](https://github.com/AntiMicro/antimicro), -which seems to have even more features and supported platforms -than QJoyPad. +Yes, ThunderPad, like QJoyPad, only works in X11/XWindows environments. For Wayland or console applications, you'll need to use alternative solutions like [joy2key](https://sourceforge.net/projects/joy2key/) or [AntiMicro](https://github.com/AntiMicro/antimicro). -### But my window manager doesn't HAVE a system tray! +### Why do I have to tell ThunderPad to "update joystick devices"? Why can't it do that on its own? -I'm well aware that every Linux setup is different and that -there are a million different window managers that range from -beautiful, feature-full, and bloated to stark, minimalist, and -lightning-fast. Unfortunately, after a few people suggested -that I have a tray icon for the no-gui mode, I realized that -it was a very, very good idea. The new version of QJoyPad is -built up around the system tray conceptually, and to make a -version that doesn't use it would be a lot of work, so for now -I plan to keep things as they are. - -However, to accommodate those of you who don't have a system -tray and can't stand that little icon, using the argument -`--notray` makes a floating icon that is much bigger instead of -the little tray icon. It still behaves exactly as the smaller -icon would, except it is larger and cannot be captured by the -system tray. - -### I hate the QJoyPad icon. Is there any way to change it? - -Absolutely! Starting with version 4.2 QJoyPad stores its -icons at these locations: - - $INSTALL_PREFIX/share/icons/hicolor/24x24/apps/qjoypad.png - $INSTALL_PREFIX/share/icons/hicolor/64x64/apps/qjoypad.png - -(Where `$INSTALL_PREFIX` is usually `/usr` or `/usr/local`.) - -Just replace these files and restart QJoyPad. - -### Why do I have to tell QJoyPad to "update joystick devices"? Why can't it do that on its own? - -If you compile with `-DWITH_LIBUDEV=ON` (the default) then UDev -is used to automatically update the joypad list. If automatically -updating of the joypad list still does not work compile with -`-DCMAKE_BUILD_TYPE=Debug` and post the output on the [GitHub -bug tracker](https://github.com/panzi/qjoypad/issues). +If you compile with `-DWITH_LIBUDEV=ON` (the default) then UDev is used to automatically update the joypad list. If automatically updating of the joypad list still does not work compile with `-DCMAKE_BUILD_TYPE=Debug` and post the output on the [GitHub bug tracker](https://github.com/stormux-dev/thunderpad/issues). -You can force QJoyPad to rescan your joypads at any time using the -menu or by running `qjoypad --update`. - -### When QJoyPad checks for new joysticks, it doesn't find mine! - -When you plug in a joystick, there are certain things that -have to happen for the joystick to become available to -programs like QJoyPad. Mainly, the joystick has to be -recognized and drivers have to be loaded. Even if this process -is automatic on your computer it could take a few seconds, so -if QJoyPad can't find your device right away, try again a few -moments later. If driver modules aren't loaded automatically, -don't forget to load them before you ask QJoyPad to look for -new devices. If you use a X-Box 360 pad and teh LEDs keep -blinking try to re-plug it. If you keep having troubles, see -[Joystick recognition](#joystick-recognition). - -### Why are both Up and Down treated as the same axis? - -That's because they are the same axis. An "axis" on a joystick -(or gamepad; or in math for that matter) isn't actually a -direction, but a dimension. A standard simple joystick can -move along two axes, the X-axis (side to side) and the Y-axis -(up and down); when you move the stick to the left, you're -moving it along the X-axis in the negative direction, and when -you move it to the right you're moving it in the positive -direction along the same axis. - -What really matters is that in QJoyPad, every axis represents -two opposing directions and can therefore have two different -keys. I only do it that way because thats how the device -itself works. I'd make the labels a little more intuitive, but -unfortunately what each axis corresponds to changes from -controller to controller and there's no way for me to know -which is which. If you don't know which axis to set for which -direction, move in the direction you want and see which button -lights up, or try using Quick Set instead. - -### All of this is too complicated. Why isn't there a button for Up? - -Unfortunately, adding new features means increasing complexity -and making things more confusing. That's just how things go. -If you just want to have one key pressed when you press a -button on your joystick, try using just the quick set feature -of QJoyPad 3 (and newer). There all you need to do is press what -you want to press on the joystick and then type the key you want -that button to trigger. - -Also, if you preferred the simplicity of QJoyPad 2.1, it's -still available and quite functional, it just doesn't have -quite as many options and doesn't use a system tray icon. The -two versions of QJoyPad are compatible and can both be run on -the same computer without getting in each others' way (as long -as you rename one of them so they aren't both called "qjoypad"), -just not at the same time. - -You can find old versions of QJoyPad [here](https://sourceforge.net/projects/qjoypad/files/qjoypad/). -However, they probably won't work on modern Linux distributions -because they use obsolete Qt versions. - -### Features and suggestions - -#### Why can't I click with an axis, or move the mouse with a - -#### Why doesn't QJoyPad do `_____`? - -For the sake of my sanity, I didn't program every possible -thing I could imagine someone wanting to do into QJoyPad. I -added in the features that people were asking for and which -made sense, and I set somewhat arbitrary limits on what the -user can and can't do. Why set limits? Because if I didn't the -program would get far too bulky and too time consuming to -write. I tried to draw the line at what I thought was -reasonable use. No, you can't make the mouse click whenever -you move an axis... but why would you want to? - -If there's something that you feel QJoyPad should be able to -do that it can't you might want to [write a feature -request](https://github.com/panzi/qjoypad/issues) on github. - -## Credits - -Thank you to -[Erich Kitzmüller](http://members.chello.at/erich.kitzmueller/ammoq/main.html), -author of xjoypad for the inspiration to write QJoyPad and -for the code that started Nathan Gaylinn off. - -The development team for Psi, the Jabber client, also get a -lot of thanks for writing the tray icon code that I borrowed -and tweaked. (Note from Mathias Panzenböck: I guess this is -about the tray icon code before Qt 4. Qt 4 and newer has nice support -for the tray.) Thank you for developing GPL and for helping -other developers! (Check out the [Psi Website](http://psi.affinix.com/)) - -Thank you also to everyone who has sent me an email about -QJoyPad. Knowing that my program is used and appreciated means -a lot, especially since that's about all I get out of my -programming. Open source is like teaching; it's very important -and means a lot for young and developing programmers, but it's -a time consuming and underpaid profession ;) - -Finally, I need to offer a very warm thank you to Mark -Hannessen who graciously donated one Logitech Wingman -Rumblepad to the cause of QJoyPad. Without that, I simply -would not have been able to add support for multiple axes or -throttle controls, so version 3 might have never been made. -Thank you for your interest and for your support, Mark. +You can force ThunderPad to rescan your joypads at any time using the menu or by running `thunderpad --update`. ## Licensing -This software is licensed under the terms of the GNU GPLv2. -Please see LICENSE.txt for a full text of the license. +This software is licensed under the terms of the GNU GPLv2. Please see LICENSE.txt for a full text of the license. diff --git a/qjoypad.desktop b/qjoypad.desktop deleted file mode 100755 index 14ef216..0000000 --- a/qjoypad.desktop +++ /dev/null @@ -1,13 +0,0 @@ -[Desktop Entry] -Name=QJoyPad -GenericName=Joypad to Keyboard/Mouse Mapper -GenericName[de]=Joypad zu Tastatur/Maus Mapper -GenericName[fr]=Contrôle du clavier/souris avec un joystick -Exec=qjoypad -Icon=qjoypad -Type=Application -Terminal=false -Categories=Qt;Game; -Comment=Maps joypad button and stick events to keyboard and mouse events. -Comment[de]=Bildet Joypad Knopf und Stick Ereignisse auf Tastatur und Maus Ereignisse ab. -Comment[fr]=Associe les boutons et sticks directionnels d'un joystick à des événements de clavier et de souris. diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index be28387..14ce07d 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -2,7 +2,7 @@ include(GenerateExportHeader) configure_file(config.h.in "${CMAKE_CURRENT_BINARY_DIR}/config.h" @ONLY) -set(qjoypad_SOURCES +set(thunderpad_SOURCES axis.cpp axis_edit.cpp axisw.cpp @@ -22,7 +22,7 @@ set(qjoypad_SOURCES main.cpp quickset.cpp) -set(qjoypad_QOBJECT_HEADERS +set(thunderpad_QOBJECT_HEADERS axis_edit.h axis.h axisw.h @@ -40,8 +40,8 @@ set(qjoypad_QOBJECT_HEADERS layout.h quickset.h) -qt5_wrap_cpp(qjoypad_HEADERS_MOC ${qjoypad_QOBJECT_HEADERS}) -add_executable(qjoypad ${qjoypad_SOURCES} ${qjoypad_HEADERS_MOC}) -target_link_libraries(qjoypad Qt5::Widgets Qt5::X11Extras Xtst X11 ${LIBUDEV_LIBRARIES}) +qt5_wrap_cpp(thunderpad_HEADERS_MOC ${thunderpad_QOBJECT_HEADERS}) +add_executable(thunderpad ${thunderpad_SOURCES} ${thunderpad_HEADERS_MOC}) +target_link_libraries(thunderpad Qt5::Widgets Qt5::X11Extras Xtst X11 ${LIBUDEV_LIBRARIES}) -install(TARGETS qjoypad RUNTIME DESTINATION "bin") +install(TARGETS thunderpad RUNTIME DESTINATION "bin") diff --git a/src/axis.h b/src/axis.h index f7e2a5f..53d2bdc 100644 --- a/src/axis.h +++ b/src/axis.h @@ -1,5 +1,5 @@ -#ifndef QJOYPAD_AXIS_H -#define QJOYPAD_AXIS_H +#ifndef THUNDERPAD_AXIS_H +#define THUNDERPAD_AXIS_H //abs() #include diff --git a/src/axis_edit.cpp b/src/axis_edit.cpp index 816447a..fd8ccd2 100644 --- a/src/axis_edit.cpp +++ b/src/axis_edit.cpp @@ -7,7 +7,7 @@ AxisEdit::AxisEdit( Axis* ax ) //build the dialog, display current axis settings :) axis = ax; setWindowTitle("Set " + axis->getName()); - setWindowIcon(QPixmap(QJOYPAD_ICON24)); + setWindowIcon(QPixmap(THUNDERPAD_ICON24)); //h, v, and v2 are all references to layouts. They are used to refer to //various layouts as the dialog is built and are not pointing to the same diff --git a/src/axis_edit.h b/src/axis_edit.h index 6a708b3..bf50e8a 100644 --- a/src/axis_edit.h +++ b/src/axis_edit.h @@ -1,5 +1,5 @@ -#ifndef QJOYPAD_AXIS_EDIT_H -#define QJOYPAD_AXIS_EDIT_H +#ifndef THUNDERPAD_AXIS_EDIT_H +#define THUNDERPAD_AXIS_EDIT_H //to refer to the axis we're editing //for building up the dialog we need #include "axis.h" diff --git a/src/axisw.cpp b/src/axisw.cpp index 816ea46..39a42d1 100644 --- a/src/axisw.cpp +++ b/src/axisw.cpp @@ -23,6 +23,13 @@ void AxisWidget::update() { } void AxisWidget::mouseReleaseEvent( QMouseEvent* e ) { + configure(); + //release the button. Waiting to do this until the very end has the nice + //effect of keeping the button depressed while the dialog is shown. + FlashButton::mouseReleaseEvent( e ); +} + +void AxisWidget::configure() { //create the edit dialog, ae = new AxisEdit(axis); //get its input @@ -32,7 +39,4 @@ void AxisWidget::mouseReleaseEvent( QMouseEvent* e ) { //and remember that it's gone. ae = NULL; update(); - //release the button. Waiting to do this until the very end has the nice - //effect of keeping the button depressed while the dialog is shown. - FlashButton::mouseReleaseEvent( e ); } diff --git a/src/axisw.h b/src/axisw.h index 3210cac..2c71c5f 100644 --- a/src/axisw.h +++ b/src/axisw.h @@ -1,5 +1,5 @@ -#ifndef QJOYPAD_AXIS_WIDGET_H -#define QJOYPAD_AXIS_WIDGET_H +#ifndef THUNDERPAD_AXIS_WIDGET_H +#define THUNDERPAD_AXIS_WIDGET_H #include //so we can interact with the axis this refers to @@ -19,6 +19,8 @@ class AxisWidget : public FlashButton { void jsevent( int val ); //change the text on this button to reflect the axis' current state. void update(); + //public method to configure this axis (for accessibility) + void configure(); private: //to deal with clicking (by creating an AxisEdit dialog) void mouseReleaseEvent( QMouseEvent* e ); diff --git a/src/button.h b/src/button.h index ef597e1..f5d2640 100644 --- a/src/button.h +++ b/src/button.h @@ -1,5 +1,5 @@ -#ifndef QJOYPAD_BUTTON_H -#define QJOYPAD_BUTTON_H +#ifndef THUNDERPAD_BUTTON_H +#define THUNDERPAD_BUTTON_H #include #include diff --git a/src/button_edit.cpp b/src/button_edit.cpp index 6fa53c0..f585cb8 100644 --- a/src/button_edit.cpp +++ b/src/button_edit.cpp @@ -10,7 +10,7 @@ ButtonEdit::ButtonEdit(Button* butt, const QStringList *layoutNames) //build the dialog! button = butt; setWindowTitle(tr("Set %1").arg(button->getName())); - setWindowIcon(QPixmap(QJOYPAD_ICON24)); + setWindowIcon(QPixmap(THUNDERPAD_ICON24)); QVBoxLayout* v = new QVBoxLayout(this); v->setMargin(5); diff --git a/src/button_edit.h b/src/button_edit.h index 79ca72b..260b148 100644 --- a/src/button_edit.h +++ b/src/button_edit.h @@ -1,5 +1,5 @@ -#ifndef QJOYPAD_BUTTON_EDIT_H -#define QJOYPAD_BUTTON_EDIT_H +#ifndef THUNDERPAD_BUTTON_EDIT_H +#define THUNDERPAD_BUTTON_EDIT_H #include #include diff --git a/src/buttonw.cpp b/src/buttonw.cpp index ef9b0af..d69472f 100644 --- a/src/buttonw.cpp +++ b/src/buttonw.cpp @@ -19,10 +19,13 @@ void ButtonWidget::update() { } void ButtonWidget::mouseReleaseEvent( QMouseEvent* e ) { + configure(); + FlashButton::mouseReleaseEvent( e ); +} + +void ButtonWidget::configure() { ButtonEdit* be = new ButtonEdit(button, &layoutNames); be->exec(); delete be; - update(); - FlashButton::mouseReleaseEvent( e ); } diff --git a/src/buttonw.h b/src/buttonw.h index b83e72d..13b5ead 100644 --- a/src/buttonw.h +++ b/src/buttonw.h @@ -1,5 +1,5 @@ -#ifndef QJOYPAD_BUTTON_WIDGET_H -#define QJOYPAD_BUTTON_WIDGET_H +#ifndef THUNDERPAD_BUTTON_WIDGET_H +#define THUNDERPAD_BUTTON_WIDGET_H //this represents a Button #include "button.h" @@ -21,6 +21,8 @@ class ButtonWidget : public FlashButton { void jsevent( int val ); //reset the label to match the respective Button's current state. void update(); + //public method to configure this button (for accessibility) + void configure(); QStringList layoutNames; private: void mouseReleaseEvent( QMouseEvent* e ); diff --git a/src/config.h.in b/src/config.h.in index ecccddf..3941cfd 100644 --- a/src/config.h.in +++ b/src/config.h.in @@ -1,17 +1,16 @@ -#ifndef QJOYPAD_CONFIG_H_IN -#define QJOYPAD_CONFIG_H_IN +#ifndef THUNDERPAD_CONFIG_H_IN +#define THUNDERPAD_CONFIG_H_IN -#cmakedefine QJOYPAD_MAJOR -#cmakedefine QJOYPAD_MINOR -#cmakedefine QJOYPAD_PATCH +#cmakedefine THUNDERPAD_MAJOR +#cmakedefine THUNDERPAD_MINOR +#cmakedefine THUNDERPAD_PATCH -#define QJOYPAD_VERSION "@QJOYPAD_MAJOR@.@QJOYPAD_MINOR@.@QJOYPAD_PATCH@" -#define QJOYPAD_NAME "QJoyPad @QJOYPAD_MAJOR@.@QJOYPAD_MINOR@" -#define QJOYPAD_DEVDIR "@DEVICE_DIR@" +#define THUNDERPAD_VERSION "@THUNDERPAD_MAJOR@.@THUNDERPAD_MINOR@.@THUNDERPAD_PATCH@" +#define THUNDERPAD_NAME "ThunderPad @THUNDERPAD_MAJOR@.@THUNDERPAD_MINOR@" +#define THUNDERPAD_DEVDIR "@DEVICE_DIR@" -#define QJOYPAD_ICON24 "@CMAKE_INSTALL_PREFIX@/share/icons/hicolor/24x24/apps/qjoypad.png" -#define QJOYPAD_ICON64 "@CMAKE_INSTALL_PREFIX@/share/icons/hicolor/64x64/apps/qjoypad.png" -#define QJOYPAD_L10N_DIR "@CMAKE_INSTALL_PREFIX@/share/qjoypad/translations/" +#define THUNDERPAD_ICON24 "@CMAKE_INSTALL_PREFIX@/share/icons/hicolor/24x24/apps/thunderpad.png" +#define THUNDERPAD_ICON64 "@CMAKE_INSTALL_PREFIX@/share/icons/hicolor/64x64/apps/thunderpad.png" #cmakedefine WITH_LIBUDEV diff --git a/src/constant.h b/src/constant.h index 246a784..05be886 100644 --- a/src/constant.h +++ b/src/constant.h @@ -1,5 +1,5 @@ -#ifndef QJOYPAD_CONSTANT_H -#define QJOYPAD_CONSTANT_H +#ifndef THUNDERPAD_CONSTANT_H +#define THUNDERPAD_CONSTANT_H //How many cycles there are per click. #define FREQ 10 diff --git a/src/error.h b/src/error.h index 1b05a67..44b2aab 100644 --- a/src/error.h +++ b/src/error.h @@ -1,5 +1,5 @@ -#ifndef QJOYPAD_ERROR_H -#define QJOYPAD_ERROR_H +#ifndef THUNDERPAD_ERROR_H +#define THUNDERPAD_ERROR_H #include #include @@ -8,7 +8,7 @@ //a nice simple way of throwing up an error message if something goes wrong. inline void errorBox(const QString &title, const QString &message, QWidget *parent = 0) { - QMessageBox::warning(parent, QString("%1 - %2").arg(title, QJOYPAD_NAME), + QMessageBox::warning(parent, QString("%1 - %2").arg(title, THUNDERPAD_NAME), message, QMessageBox::Ok, Qt::NoButton); } diff --git a/src/event.h b/src/event.h index 584756c..5637a56 100644 --- a/src/event.h +++ b/src/event.h @@ -1,12 +1,12 @@ -#ifndef QJOYPAD_EVENT_H -#define QJOYPAD_EVENT_H +#ifndef THUNDERPAD_EVENT_H +#define THUNDERPAD_EVENT_H //for the functions we need to generate keypresses / mouse actions #include //a simplified event structure that can handle buttons and mouse movements struct FakeEvent { - //types of events QJoyPad can create. + //types of events ThunderPad can create. //KeyRelease, KeyPress, ButtonRelease, ButtonPress, and MouseMove enum EventType {KeyUp, KeyDown, MouseUp, MouseDown, MouseMove, MouseMoveAbsolute}; diff --git a/src/flash.h b/src/flash.h index 116a6cc..b7ca7ee 100644 --- a/src/flash.h +++ b/src/flash.h @@ -1,5 +1,5 @@ -#ifndef QJOYPAD_FLASH_H -#define QJOYPAD_FLASH_H +#ifndef THUNDERPAD_FLASH_H +#define THUNDERPAD_FLASH_H #include #include diff --git a/src/icon.cpp b/src/icon.cpp index 83a5f89..5e369ab 100644 --- a/src/icon.cpp +++ b/src/icon.cpp @@ -9,7 +9,7 @@ FloatingIcon::FloatingIcon( const QString &icon, QMenu *popup, QWidget *parent, setAttribute(Qt::WA_QuitOnClose); setAttribute(Qt::WA_TranslucentBackground); setWindowFlags(Qt::FramelessWindowHint); - setWindowTitle(tr("%1 Floating Icon").arg(QJOYPAD_NAME)); + setWindowTitle(tr("%1 Floating Icon").arg(THUNDERPAD_NAME)); pop = popup; setFixedSize(this->icon.width(),this->icon.height()); diff --git a/src/icon.h b/src/icon.h index e009564..0d8ca5b 100644 --- a/src/icon.h +++ b/src/icon.h @@ -1,5 +1,5 @@ -#ifndef QJOYPAD_ICON_H -#define QJOYPAD_ICON_H +#ifndef THUNDERPAD_ICON_H +#define THUNDERPAD_ICON_H #include #include diff --git a/src/joypad.h b/src/joypad.h index 731bbf8..b5c8b77 100644 --- a/src/joypad.h +++ b/src/joypad.h @@ -1,5 +1,5 @@ -#ifndef QJOYPAD_JOYPAD_H -#define QJOYPAD_JOYPAD_H +#ifndef THUNDERPAD_JOYPAD_H +#define THUNDERPAD_JOYPAD_H //parts of the joypad #include "button.h" diff --git a/src/joypadw.cpp b/src/joypadw.cpp index 86f85d5..a0329b6 100644 --- a/src/joypadw.cpp +++ b/src/joypadw.cpp @@ -2,46 +2,112 @@ JoyPadWidget::JoyPadWidget( JoyPad* jp, int i, QWidget* parent ) : QWidget(parent) { - //initialize things, build the dialog + //initialize things, build the accessible dialog joypad = jp; index = i; - /* This was in below, no idea what it does :( ... - * (joypad->axes+1)/2 +(joypad->buttons+1)/2 + 2 - */ - layoutMain = new QGridLayout(this); - layoutMain->setSpacing(5); - layoutMain->setMargin(5); flashcount = 0; - int insertCounter = 0; quickset = NULL; + // Create main vertical layout + layoutMain = new QVBoxLayout(this); + layoutMain->setSpacing(10); + layoutMain->setMargin(10); + + // Create horizontal layout for axes and buttons groups + topLayout = new QHBoxLayout(); + + // Create axes group + axesGroup = new QGroupBox("Axes", this); + QVBoxLayout *axesLayout = new QVBoxLayout(axesGroup); + + axesList = new QListWidget(axesGroup); + axesList->setAccessibleName("Axes List"); + axesList->setAccessibleDescription("List of joystick axes for configuration"); + axesLayout->addWidget(axesList); + + btnConfigureAxis = new QPushButton("Configure Selected Axis", axesGroup); + btnConfigureAxis->setEnabled(false); + btnConfigureAxis->setAccessibleDescription("Configure the currently selected axis"); + btnConfigureAxis->setFocusPolicy(Qt::TabFocus); + connect(btnConfigureAxis, SIGNAL(clicked()), this, SLOT(configureSelectedAxis())); + axesLayout->addWidget(btnConfigureAxis); + + axisStatusLabel = new QLabel("Select an axis to configure", axesGroup); + axisStatusLabel->setWordWrap(true); + axesLayout->addWidget(axisStatusLabel); + + // Create buttons group + buttonsGroup = new QGroupBox("Buttons", this); + QVBoxLayout *buttonsLayout = new QVBoxLayout(buttonsGroup); + + buttonsList = new QListWidget(buttonsGroup); + buttonsList->setAccessibleName("Buttons List"); + buttonsList->setAccessibleDescription("List of joystick buttons for configuration"); + buttonsLayout->addWidget(buttonsList); + + btnConfigureButton = new QPushButton("Configure Selected Button", buttonsGroup); + btnConfigureButton->setEnabled(false); + btnConfigureButton->setAccessibleDescription("Configure the currently selected button"); + btnConfigureButton->setFocusPolicy(Qt::TabFocus); + connect(btnConfigureButton, SIGNAL(clicked()), this, SLOT(configureSelectedButton())); + buttonsLayout->addWidget(btnConfigureButton); + + buttonStatusLabel = new QLabel("Select a button to configure", buttonsGroup); + buttonStatusLabel->setWordWrap(true); + buttonsLayout->addWidget(buttonStatusLabel); + + // Add groups to horizontal layout + topLayout->addWidget(axesGroup); + topLayout->addWidget(buttonsGroup); + layoutMain->addLayout(topLayout); + + // Create the underlying widgets for compatibility foreach (Axis *axis, joypad->axes) { - AxisWidget *aw = new AxisWidget(axis,this); + AxisWidget *aw = new AxisWidget(axis, this); + aw->setVisible(false); // Hide the old widgets axes.append(aw); connect( aw, SIGNAL( flashed( bool ) ), this, SLOT( flash( bool ))); - layoutMain->addWidget(aw, insertCounter / 2, insertCounter % 2); - insertCounter++; } foreach (Button *button, joypad->buttons) { - ButtonWidget *bw = new ButtonWidget(button,this); + ButtonWidget *bw = new ButtonWidget(button, this); + bw->setVisible(false); // Hide the old widgets buttons.append(bw); connect( bw, SIGNAL( flashed( bool ) ), this, SLOT( flash( bool ))); - layoutMain->addWidget(bw, insertCounter / 2, insertCounter % 2); - insertCounter++; } - if (insertCounter % 2 == 1) { - insertCounter ++; - } - insertCounter += 2; - btnClear = new QPushButton(QIcon::fromTheme("edit-clear"), tr("Clear"), this); + // Control buttons + QHBoxLayout *controlLayout = new QHBoxLayout(); + btnClear = new QPushButton(QIcon::fromTheme("edit-clear"), "Clear All", this); + btnClear->setAccessibleDescription("Clear all axis and button configurations"); + btnClear->setFocusPolicy(Qt::StrongFocus); + btnClear->setAccessibleName("Clear All Button"); connect(btnClear, SIGNAL(clicked()), this, SLOT(clear())); - layoutMain->addWidget(btnClear, insertCounter / 2, insertCounter % 2); - insertCounter++; - btnAll = new QPushButton(tr("Quick Set"), this); - layoutMain->addWidget(btnAll, insertCounter / 2, insertCounter % 2); + controlLayout->addWidget(btnClear); + + btnAll = new QPushButton("Quick Set", this); + btnAll->setAccessibleDescription("Quick configuration mode for all controls"); + btnAll->setFocusPolicy(Qt::StrongFocus); // Try StrongFocus instead of TabFocus + btnAll->setAccessibleName("Quick Set Button"); connect(btnAll, SIGNAL(clicked()), this, SLOT(setAll())); + controlLayout->addWidget(btnAll); + + controlLayout->addStretch(); + layoutMain->addLayout(controlLayout); + + // Connect selection change signals + connect(axesList, SIGNAL(itemSelectionChanged()), this, SLOT(onAxisSelectionChanged())); + connect(buttonsList, SIGNAL(itemSelectionChanged()), this, SLOT(onButtonSelectionChanged())); + + // Set explicit tab order to ensure all widgets are accessible + setTabOrder(axesList, btnConfigureAxis); + setTabOrder(btnConfigureAxis, buttonsList); + setTabOrder(buttonsList, btnConfigureButton); + setTabOrder(btnConfigureButton, btnClear); + setTabOrder(btnClear, btnAll); + + // Populate the lists + update(); } JoyPadWidget::~JoyPadWidget() { @@ -63,12 +129,28 @@ void JoyPadWidget::flash( bool on ) { } void JoyPadWidget::update() { + // Update underlying widgets foreach (AxisWidget *axis, axes) { axis->update(); } foreach (ButtonWidget *button, buttons) { button->update(); } + + // Update accessible lists + axesList->clear(); + for (int i = 0; i < axes.size(); i++) { + QString axisName = QString("Axis %1").arg(i + 1); + QString axisDesc = axes[i]->text(); // Get current configuration description + axesList->addItem(QString("%1: %2").arg(axisName, axisDesc)); + } + + buttonsList->clear(); + for (int i = 0; i < buttons.size(); i++) { + QString buttonName = QString("Button %1").arg(i + 1); + QString buttonDesc = buttons[i]->text(); // Get current configuration description + buttonsList->addItem(QString("%1: %2").arg(buttonName, buttonDesc)); + } } void JoyPadWidget::clear() { @@ -108,4 +190,52 @@ void JoyPadWidget::updateButtonLayoutLists(const QStringList layoutNames) { foreach (ButtonWidget *bw, buttons) { bw->layoutNames = layoutNames; } +} + +void JoyPadWidget::configureSelectedAxis() { + int selectedRow = axesList->currentRow(); + if (selectedRow >= 0 && selectedRow < axes.size()) { + // Use the public configure method for accessibility + axes[selectedRow]->configure(); + // Update the display after configuration + update(); + } +} + +void JoyPadWidget::configureSelectedButton() { + int selectedRow = buttonsList->currentRow(); + if (selectedRow >= 0 && selectedRow < buttons.size()) { + // Use the public configure method for accessibility + buttons[selectedRow]->configure(); + // Update the display after configuration + update(); + } +} + +void JoyPadWidget::onAxisSelectionChanged() { + bool hasSelection = axesList->currentRow() >= 0; + btnConfigureAxis->setEnabled(hasSelection); + + if (hasSelection) { + int selectedRow = axesList->currentRow(); + if (selectedRow < axes.size()) { + axisStatusLabel->setText(QString("Selected: %1").arg(axesList->currentItem()->text())); + } + } else { + axisStatusLabel->setText("Select an axis to configure"); + } +} + +void JoyPadWidget::onButtonSelectionChanged() { + bool hasSelection = buttonsList->currentRow() >= 0; + btnConfigureButton->setEnabled(hasSelection); + + if (hasSelection) { + int selectedRow = buttonsList->currentRow(); + if (selectedRow < buttons.size()) { + buttonStatusLabel->setText(QString("Selected: %1").arg(buttonsList->currentItem()->text())); + } + } else { + buttonStatusLabel->setText("Select a button to configure"); + } } \ No newline at end of file diff --git a/src/joypadw.h b/src/joypadw.h index 56c9772..7c6766e 100644 --- a/src/joypadw.h +++ b/src/joypadw.h @@ -1,10 +1,16 @@ -#ifndef QJOYPAD_JOYPAD_WIDGET_H -#define QJOYPAD_JOYPAD_WIDGET_H +#ifndef THUNDERPAD_JOYPAD_WIDGET_H +#define THUNDERPAD_JOYPAD_WIDGET_H //parts for the widget //Added by qt3to4: #include +#include +#include +#include +#include +#include +#include #include #include "axisw.h" //this all relates to a JoyPad @@ -38,6 +44,11 @@ class JoyPadWidget : public QWidget { void clear(); //quickset! void setAll(); + //accessible configuration slots + void configureSelectedAxis(); + void configureSelectedButton(); + void onAxisSelectionChanged(); + void onButtonSelectionChanged(); signals: //happens whenever the tab that represents this joypadwidget should flash //(either on or off) The int is the index of this widget so that this @@ -56,10 +67,15 @@ class JoyPadWidget : public QWidget { int flashcount; //the parts of the dialog - QGridLayout *layoutMain; + QVBoxLayout *layoutMain; + QHBoxLayout *topLayout; + QGroupBox *axesGroup, *buttonsGroup; + QListWidget *axesList, *buttonsList; + QPushButton *btnConfigureAxis, *btnConfigureButton; + QPushButton *btnClear, *btnAll; + QLabel *axisStatusLabel, *buttonStatusLabel; QList axes; QList buttons; - QPushButton *btnClear, *btnAll; //the quickset window, when we create it QuickSet* quickset; diff --git a/src/joyslider.h b/src/joyslider.h index 405966f..823f95f 100644 --- a/src/joyslider.h +++ b/src/joyslider.h @@ -1,5 +1,5 @@ -#ifndef QJOYPAD_JOYSLIDER_H -#define QJOYPAD_JOYSLIDER_H +#ifndef THUNDERPAD_JOYSLIDER_H +#define THUNDERPAD_JOYSLIDER_H //the parent of this diff --git a/src/keycode.h b/src/keycode.h index 4ed006c..aad29c6 100644 --- a/src/keycode.h +++ b/src/keycode.h @@ -1,5 +1,5 @@ -#ifndef QJOYPAD_KEYCODE_H -#define QJOYPAD_KEYCODE_H +#ifndef THUNDERPAD_KEYCODE_H +#define THUNDERPAD_KEYCODE_H //To create the "press a key" dialog: #include diff --git a/src/layout.cpp b/src/layout.cpp index f705c9d..8184c9d 100644 --- a/src/layout.cpp +++ b/src/layout.cpp @@ -13,11 +13,11 @@ LayoutManager::LayoutManager( bool useTrayIcon, const QString &devdir, const QString &settingsDir ) : devdir(devdir), settingsDir(settingsDir), layoutGroup(new QActionGroup(this)), - updateDevicesAction(new QAction(QIcon::fromTheme("view-refresh"),tr("Update &Joystick Devices"),this)), - updateLayoutsAction(new QAction(QIcon::fromTheme("view-refresh"),tr("Update &Layout List"),this)), - addNewConfiguration(new QAction(QIcon::fromTheme("list-add"),tr("Add new configuration"),this)), - quitAction(new QAction(QIcon::fromTheme("application-exit"),tr("&Quit"),this)), - le(0) { + updateDevicesAction(new QAction(QIcon::fromTheme("view-refresh"),"Update &Joystick Devices",this)), + updateLayoutsAction(new QAction(QIcon::fromTheme("view-refresh"),"Update &Layout List",this)), + addNewConfiguration(new QAction(QIcon::fromTheme("list-add"),"Add new configuration",this)), + quitAction(new QAction(QIcon::fromTheme("application-exit"),"&Quit",this)), + le(0), isNotrayMode(!useTrayIcon) { #ifdef WITH_LIBUDEV udevNotifier = 0; @@ -25,8 +25,8 @@ LayoutManager::LayoutManager( bool useTrayIcon, const QString &devdir, const QSt monitor = 0; if (!initUDev()) { - errorBox(tr("UDev Error"), tr("Error creating UDev monitor. " - "QJoyPad will still work, but it won't automatically update the joypad device list.")); + errorBox("UDev Error", "Error creating UDev monitor. " + "ThunderPad will still work, but it won't automatically update the joypad device list."); } #endif @@ -37,17 +37,14 @@ LayoutManager::LayoutManager( bool useTrayIcon, const QString &devdir, const QSt if (useTrayIcon) { QSystemTrayIcon *tray = new QSystemTrayIcon(this); tray->setContextMenu(&trayMenu); - tray->setIcon(QIcon(QJOYPAD_ICON24)); + tray->setIcon(QIcon(THUNDERPAD_ICON24)); tray->show(); connect(tray, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), this, SLOT(trayClick(QSystemTrayIcon::ActivationReason))); } - //or make a floating icon + //in notray mode, just show the configuration window directly else { - FloatingIcon* icon = new FloatingIcon(QJOYPAD_ICON64,&trayMenu,0,"tray"); - connect(icon, SIGNAL(clicked()), this, SLOT(iconClick())); - connect(icon, SIGNAL(rejected()), qApp, SLOT(quit())); - connect(icon, SIGNAL(accepted()), qApp, SLOT(quit())); - icon->show(); + // Automatically show the configuration window for accessibility + addNewConfig(); } connect(updateLayoutsAction, SIGNAL(triggered()), this, SLOT(fillPopup())); @@ -316,7 +313,7 @@ void LayoutManager::save(QFile &file) { //if it's good, start writing the file if (file.open(QIODevice::WriteOnly)) { QTextStream stream( &file ); - stream << "# " QJOYPAD_NAME " Layout File\n\n"; + stream << "# " THUNDERPAD_NAME " Layout File\n\n"; foreach (JoyPad *joypad, joypads) { joypad->write( stream ); } @@ -332,8 +329,8 @@ void LayoutManager::saveAs() { bool ok = false; //request a new name! QString name = QInputDialog::getText(le, - tr("Name new layout - %1").arg(QJOYPAD_NAME), - tr("Enter a name for the new layout:"), + QString("Name new layout - %1").arg(THUNDERPAD_NAME), + "Enter a name for the new layout:", QLineEdit::Normal, QString(), &ok); if (!ok) { return; @@ -368,11 +365,11 @@ void LayoutManager::saveAs() { void LayoutManager::importLayout() { QFileDialog dialog(le); - dialog.setWindowTitle(tr("Import layout - %1").arg(QJOYPAD_NAME)); + dialog.setWindowTitle(QString("Import layout - %1").arg(THUNDERPAD_NAME)); dialog.setFileMode(QFileDialog::ExistingFile); dialog.setAcceptMode(QFileDialog::AcceptOpen); QStringList filters; - filters.append(tr("QJoyPad layout files (*.lyt)")); + filters.append("ThunderPad layout files (*.lyt)"); filters.append(tr("Any files (*)")); dialog.setNameFilters(filters); dialog.setDefaultSuffix("lyt"); @@ -388,13 +385,13 @@ void LayoutManager::importLayout() { QString filename = getFileName(layoutName); if (info == QFileInfo(filename)) { - errorBox(tr("Import error"), tr("Cannot import file from QJoyPad settings directory.")); + errorBox("Import error", "Cannot import file from ThunderPad settings directory."); return; } if (QFile::exists(filename)) { if (QMessageBox::warning(le, - QString("%1 - %2").arg(tr("Layout exists"), QJOYPAD_NAME), + QString("%1 - %2").arg("Layout exists", THUNDERPAD_NAME), tr("Layout \"%1\" exists. Do you want to overwrite it?").arg(layoutName), tr("Over&write"), tr("&Cancel"), QString(), 0, 1) == 1) { return; @@ -414,11 +411,11 @@ void LayoutManager::importLayout() { void LayoutManager::exportLayout() { QFileDialog dialog(le); - dialog.setWindowTitle(tr("Export layout - %1").arg(QJOYPAD_NAME)); + dialog.setWindowTitle(QString("Export layout - %1").arg(THUNDERPAD_NAME)); dialog.setFileMode(QFileDialog::AnyFile); dialog.setAcceptMode(QFileDialog::AcceptSave); QStringList filters; - filters.append(tr("QJoyPad layout files (*.lyt)")); + filters.append("ThunderPad layout files (*.lyt)"); filters.append(tr("Any files (*)")); dialog.setNameFilters(filters); dialog.setDefaultSuffix("lyt"); @@ -437,7 +434,7 @@ void LayoutManager::saveDefault() { void LayoutManager::remove() { if (currentLayout.isNull()) return; - if (QMessageBox::warning(le, tr("Delete layout? - %1").arg(QJOYPAD_NAME), + if (QMessageBox::warning(le, QString("Delete layout? - %1").arg(THUNDERPAD_NAME), tr("Remove layout %1 permanently from your hard drive?").arg(currentLayout), tr("&Delete"), tr("&Cancel"), QString(), 0, 1 ) == 1) { return; } @@ -457,7 +454,7 @@ void LayoutManager::rename() { if (currentLayout.isNull()) return; bool ok = false; QString name = QInputDialog::getText(le, - tr("Rename layout - %1").arg(QJOYPAD_NAME), + QString("Rename layout - %1").arg(THUNDERPAD_NAME), tr("Enter a new name for the layout:"), QLineEdit::Normal, currentLayout, &ok); if (!ok) { @@ -555,7 +552,7 @@ void LayoutManager::fillPopup() { trayMenu.addSeparator(); //add null layout - QAction *action = trayMenu.addAction(tr("[NO LAYOUT]")); + QAction *action = trayMenu.addAction("[NO LAYOUT]"); action->setCheckable(true); action->setActionGroup(layoutGroup); //put a check by the current one ;) @@ -683,6 +680,11 @@ void LayoutManager::addNewConfig() { // make a new LayoutEdit dialog and show it. le = new LayoutEdit(this); le->setLayout(currentLayout); + + // In notray mode, quit app when main window closes + if (isNotrayMode) { + connect(le, SIGNAL(destroyed()), qApp, SLOT(quit())); + } } if (le) { if (le->isActiveWindow()) { diff --git a/src/layout.h b/src/layout.h index f1cc0f5..9bdba01 100644 --- a/src/layout.h +++ b/src/layout.h @@ -1,9 +1,9 @@ -#ifndef QJOYPAD_LAYOUT_H -#define QJOYPAD_LAYOUT_H +#ifndef THUNDERPAD_LAYOUT_H +#define THUNDERPAD_LAYOUT_H //to allow for interprocess communications (ie, signaling a running instance of -//qjoypad by running "qjoypad layout-name", etc.) QJoyPad uses signals to +//thunderpad by running "thunderpad layout-name", etc.) ThunderPad uses signals to //triger certain events. This is for signaling the main program to update //the joystick device list. #include @@ -109,6 +109,7 @@ class LayoutManager : public QObject { QHash available; QHash joypads; + bool isNotrayMode; #ifdef WITH_LIBUDEV bool initUDev(); diff --git a/src/layout_edit.cpp b/src/layout_edit.cpp index 222b805..96c61f1 100644 --- a/src/layout_edit.cpp +++ b/src/layout_edit.cpp @@ -6,8 +6,7 @@ LayoutEdit::LayoutEdit( LayoutManager* l ) : QWidget(0), lm(l), mainLayout(0), - padStack(0), - joyButtons(0), + joypadTabs(0), cmbLayouts(0), btnAdd(0), btnRem(0), @@ -17,8 +16,8 @@ LayoutEdit::LayoutEdit( LayoutManager* l ) btnImport(0), btnRename(0) { setAttribute(Qt::WA_DeleteOnClose); - setWindowTitle( QJOYPAD_NAME ); - setWindowIcon(QPixmap(QJOYPAD_ICON64)); + setWindowTitle( THUNDERPAD_NAME ); + setWindowIcon(QPixmap(THUNDERPAD_ICON64)); mainLayout = new QVBoxLayout(this); mainLayout->setSpacing(5); @@ -35,7 +34,7 @@ LayoutEdit::LayoutEdit( LayoutManager* l ) //most of these buttons can link directly into slots in the LayoutManager btnAdd = new QPushButton(frame); btnAdd->setIcon(QIcon::fromTheme("list-add")); - btnAdd->setToolTip(tr("Add Layout")); + btnAdd->setToolTip("Add Layout"); if (btnAdd->icon().isNull()) { btnAdd->setText("+"); } @@ -47,12 +46,12 @@ LayoutEdit::LayoutEdit( LayoutManager* l ) if (btnRem->icon().isNull()) { btnRem->setText("-"); } - btnRem->setToolTip(tr("Remove Layout")); + btnRem->setToolTip("Remove Layout"); btnRem->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); connect(btnRem, SIGNAL(clicked()), lm, SLOT(remove())); - btnRename = new QPushButton(tr("&Rename"), frame); - btnRename->setToolTip(tr("Rename Layout")); + btnRename = new QPushButton("&Rename", frame); + btnRename->setToolTip("Rename Layout"); btnRename->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); connect(btnRename, SIGNAL(clicked()), lm, SLOT(rename())); @@ -63,64 +62,46 @@ LayoutEdit::LayoutEdit( LayoutManager* l ) layoutLayout->addWidget(btnRename); mainLayout->addLayout(layoutLayout); - btnImport = new QPushButton(QIcon::fromTheme("document-open"), tr("&Import"), frame); + btnImport = new QPushButton(QIcon::fromTheme("document-open"), "&Import", frame); connect(btnImport, SIGNAL(clicked()), lm, SLOT(importLayout())); g->addWidget(btnImport,1,0); - btnExport = new QPushButton(QIcon::fromTheme("document-save-as"), tr("E&xport"), frame); + btnExport = new QPushButton(QIcon::fromTheme("document-save-as"), "E&xport", frame); connect(btnExport, SIGNAL(clicked()), lm, SLOT(exportLayout())); g->addWidget(btnExport,1,1); - btnUpd = new QPushButton(QIcon::fromTheme("document-save"), tr("&Save"), frame); + btnUpd = new QPushButton(QIcon::fromTheme("document-save"), "&Save", frame); connect(btnUpd, SIGNAL(clicked()), lm, SLOT(save())); g->addWidget(btnUpd,1,2); - btnRev = new QPushButton(QIcon::fromTheme("document-revert"), tr("Re&vert"), frame); + btnRev = new QPushButton(QIcon::fromTheme("document-revert"), "Re&vert", frame); connect(btnRev, SIGNAL(clicked()), lm, SLOT(reload())); g->addWidget(btnRev,1,3); mainLayout->addWidget( frame ); - //produce a list of names for the FlashRadioArray - //this is only necesary since joystick devices need not always be - //contiguous - QStringList names; - foreach (JoyPad *joypad, lm->available) { - names.append(joypad->getName()); - connect(this, SIGNAL(focusStateChanged(bool)), joypad, SLOT(focusChange(bool))); - } - - //flash radio array - joyButtons = new FlashRadioArray(names, true, this ); - mainLayout->addWidget( joyButtons ); - - //we have a WidgetStack to represent the multiple joypads - padScroll = new QScrollArea(this); - padScroll->setWidgetResizable(true); - mainLayout->addWidget(padScroll); - padStack = new QStackedWidget( this ); - padStack->setFrameStyle(QFrame::Box | QFrame::Sunken ); - padScroll->setWidget(padStack); + //create a tab widget for joystick devices - much more accessible + joypadTabs = new QTabWidget(this); + joypadTabs->setTabPosition(QTabWidget::North); + mainLayout->addWidget(joypadTabs); //go through each of the available joysticks - // i is the current index into PadStack - int i = 0; foreach (JoyPad *joypad, lm->available) { - //add a new JoyPadWidget to the stack - padStack->insertWidget( i, joypad->widget(padStack,i) ); - //every time it "flashes", flash the associated tab. - connect( padStack->widget(i), SIGNAL( flashed( int ) ), joyButtons, SLOT( flash( int ))); - ++i; + connect(this, SIGNAL(focusStateChanged(bool)), joypad, SLOT(focusChange(bool))); + //create accessible widget and add as tab + QScrollArea *scroll = new QScrollArea(); + scroll->setWidgetResizable(true); + JoyPadWidget *widget = joypad->widget(scroll, joypad->getIndex()); + scroll->setWidget(widget); + joypadTabs->addTab(scroll, joypad->getName()); } - //whenever a new tab is selected, raise the appropriate JoyPadWidget - connect( joyButtons, SIGNAL( changed( int ) ), padStack, SLOT( setCurrentIndex( int ))); updateLayoutList(); //add the buttons at the bottom. - QPushButton* close = new QPushButton(QIcon::fromTheme("window-close"), tr("&Close Dialog"), this ); + QPushButton* close = new QPushButton(QIcon::fromTheme("window-close"), "&Close Dialog", this ); connect(close, SIGNAL(clicked()), this, SLOT(close())); - QPushButton* quit = new QPushButton(QIcon::fromTheme("application-exit"), tr("&Quit"), this ); + QPushButton* quit = new QPushButton(QIcon::fromTheme("application-exit"), "&Quit", this ); connect( quit, SIGNAL( clicked() ), qApp, SLOT(quit())); QHBoxLayout* h = new QHBoxLayout(); @@ -150,15 +131,21 @@ void LayoutEdit::setLayout(const QString &layout) { btnRename->setEnabled(hasLayout); //update all the JoyPadWidgets. - for (int i = 0, n = lm->available.count(); i < n; i++) { - ((JoyPadWidget*)padStack->widget(i))->update(); + for (int i = 0; i < joypadTabs->count(); i++) { + QScrollArea *scroll = qobject_cast(joypadTabs->widget(i)); + if (scroll) { + JoyPadWidget *jpw = qobject_cast(scroll->widget()); + if (jpw) { + jpw->update(); + } + } } } void LayoutEdit::updateLayoutList() { //blank the list, then load in new names from the LayoutManager. cmbLayouts->clear(); - cmbLayouts->addItem(tr("[NO LAYOUT]"), QVariant(QString())); + cmbLayouts->addItem("[NO LAYOUT]", QVariant(QString())); if (lm->currentLayout.isNull()) { cmbLayouts->setCurrentIndex(0); } @@ -169,38 +156,35 @@ void LayoutEdit::updateLayoutList() { } } //Update layout list for all button edit widgets - for (int i = 0, n = lm->available.count(); i < n; i++) { + for (int i = 0; i < joypadTabs->count(); i++) { const QStringList layoutNames = lm->getLayoutNames(); - ((JoyPadWidget*)padStack->widget(i))->updateButtonLayoutLists(layoutNames); + QScrollArea *scroll = qobject_cast(joypadTabs->widget(i)); + if (scroll) { + JoyPadWidget *jpw = qobject_cast(scroll->widget()); + if (jpw) { + jpw->updateButtonLayoutLists(layoutNames); + } + } } } void LayoutEdit::updateJoypadWidgets() { - int indexOfFlashRadio = mainLayout->indexOf(joyButtons); - FlashRadioArray *newJoyButtons; - QStringList names; - foreach (JoyPad *joypad, lm->available) { - names.append(joypad->getName()); + // Clear existing tabs + while (joypadTabs->count() > 0) { + QWidget *widget = joypadTabs->widget(0); + joypadTabs->removeTab(0); + widget->deleteLater(); } - newJoyButtons = new FlashRadioArray( names, true, this ); - mainLayout->insertWidget(indexOfFlashRadio, newJoyButtons); - mainLayout->removeWidget(joyButtons); - FlashRadioArray* oldJoyButtons = joyButtons; - joyButtons = newJoyButtons; - connect( joyButtons, SIGNAL( changed( int ) ), padStack, SLOT( setCurrentIndex( int ))); - oldJoyButtons->deleteLater(); - int numberOfJoypads = padStack->count(); - for(int i = 0; iremoveWidget(padStack->widget(0)); - } - int i = 0; + // Add tabs for each available joypad foreach (JoyPad *joypad, lm->available) { - //add a new JoyPadWidget to the stack - padStack->insertWidget( i, joypad->widget(padStack,i) ); - //every time it "flashes", flash the associated tab. - connect( padStack->widget(i), SIGNAL( flashed( int ) ), joyButtons, SLOT( flash( int ))); - ++i; + connect(this, SIGNAL(focusStateChanged(bool)), joypad, SLOT(focusChange(bool))); + // Create accessible widget and add as tab + QScrollArea *scroll = new QScrollArea(); + scroll->setWidgetResizable(true); + JoyPadWidget *widget = joypad->widget(scroll, joypad->getIndex()); + scroll->setWidget(widget); + joypadTabs->addTab(scroll, joypad->getName()); } } diff --git a/src/layout_edit.h b/src/layout_edit.h index e3b37fb..5ab546d 100644 --- a/src/layout_edit.h +++ b/src/layout_edit.h @@ -1,11 +1,8 @@ -#ifndef QJOYPAD_LAYOUT_EDIT_H -#define QJOYPAD_LAYOUT_EDIT_H +#ifndef THUNDERPAD_LAYOUT_EDIT_H +#define THUNDERPAD_LAYOUT_EDIT_H #include -#include - -//for the tab list of joypads -#include "flash.h" +#include //this is a front end for the non-GUI LayoutManager class LayoutEdit; #include "layout.h" @@ -34,9 +31,7 @@ class LayoutEdit : public QWidget { LayoutManager* lm; //parts of the dialog: QVBoxLayout *mainLayout; - QScrollArea *padScroll; - QStackedWidget *padStack; - FlashRadioArray *joyButtons; + QTabWidget *joypadTabs; QComboBox* cmbLayouts; QPushButton *btnAdd, *btnRem, *btnUpd, *btnRev, *btnExport, *btnImport, *btnRename; }; diff --git a/src/main.cpp b/src/main.cpp index 83af64f..11a589f 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -10,7 +10,6 @@ #include #include #include -#include //to load layouts #include "layout.h" @@ -25,7 +24,7 @@ QPointer layoutManagerPtr; //signal handler for SIGUSR2 //SIGUSR2 means that a new layout should be loaded. It is saved in -// ~/.config/qjoypad4/layout, where the last used layout is put. +// ~/.config/thunderpad/layout, where the last used layout is put. void catchSIGUSR2( int sig ) { if (layoutManagerPtr) layoutManagerPtr->load(); //remember to catch this signal again next time. @@ -49,53 +48,28 @@ int main( int argc, char **argv ) //create a new event loop. This will be captured by the QApplication //when it gets created QApplication app( argc, argv ); - QTranslator translator; app.setQuitOnLastWindowClosed(false); - if (translator.load(QLocale::system(), "qjoypad", "_", QJOYPAD_L10N_DIR)) { - app.installTranslator(&translator); - } - else { - debug_mesg("no translation for locale: %s\n", qPrintable(QLocale::system().name())); - } - - //where QJoyPad saves its settings! - const QString settingsDir(QDir::homePath() + "/.config/qjoypad4/"); + //where ThunderPad saves its settings! + const QString settingsDir(QDir::homePath() + "/.config/thunderpad/"); //where to look for settings. If it does not exist, it will be created QDir dir(settingsDir); - //legacy QJoyPad settings location - const QString legacySettingsDir(QDir::homePath() + "/.qjoypad3/"); - //where to look for legacy settings. If it exists, it will be moved - QDir legacyDir(legacySettingsDir); - - - if (legacyDir.exists()) { - errorBox(app.translate("main","Legacy settings directory detected"), - app.translate("main","We've detected settings in ~/.qjoypad3/. For standardization purposes, we're moving them to ~/.config/qjoypad4\n\nQJoyPad will continue to work as expected")); - - if(!dir.rename(legacySettingsDir, settingsDir)) { - errorBox(app.translate("main","Could not move settings"), - app.translate("main","We could not move your settings - This likely means \"%1\" already exists on your system.\n\nPlease move files from \"%2\" to \"%1\" manually, then restart the application.").arg(settingsDir).arg(legacySettingsDir)); - return 1; - } - } - //the directory in which the joystick devices are (e.g. "/dev/input") - QString devdir = QJOYPAD_DEVDIR; + QString devdir = THUNDERPAD_DEVDIR; //if there is no new directory and we can't make it, complain if (!dir.exists() && !dir.mkdir(settingsDir)) { - errorBox(app.translate("main","Couldn't create the QJoyPad save directory"), - app.translate("main","Couldn't create the QJoyPad save directory: %1").arg(settingsDir)); + errorBox("Couldn't create the ThunderPad save directory", + QString("Couldn't create the ThunderPad save directory: %1").arg(settingsDir)); return 1; } //start out with no special layout. QString layout; - //by default, we use a tray icon - bool useTrayIcon = true; + //by default, we do NOT use a tray icon (more accessible) + bool useTrayIcon = false; //this execution wasn't made to update the joystick device list. bool update = false; bool forceTrayIcon = false; @@ -104,7 +78,7 @@ int main( int argc, char **argv ) struct option long_options[] = { {"help", no_argument, 0, 'h'}, {"device", required_argument, 0, 'd'}, - {"force-tray", no_argument, 0, 't'}, + {"tray", no_argument, 0, 't'}, {"notray", no_argument, 0, 'T'}, {"update", no_argument, 0, 'u'}, {0, 0, 0, 0 } @@ -118,22 +92,22 @@ int main( int argc, char **argv ) switch (c) { case 'h': - printf("%s", qPrintable(app.translate("main","%1\n" - "Usage: %2 [--device=\"/device/path\"] [--notray|--force-tray] [\"layout name\"]\n" + printf("%s\n" + "Usage: %s [--device=\"/device/path\"] [--tray|--notray] [\"layout name\"]\n" "\n" "Options:\n" " -h, --help Print this help message.\n" " -d, --device=PATH Look for joystick devices in PATH. This should\n" " be something like \"/dev/input\" if your game\n" " devices are in /dev/input/js0, /dev/input/js1, etc.\n" - " -t, --force-tray Force to use a system tray icon.\n" - " -T, --notray Do not use a system tray icon. This is useful for\n" - " window managers that don't support this feature.\n" - " -u, --update Force a running instance of QJoyPad to update its\n" + " -t, --tray Use a system tray icon instead of floating window.\n" + " -T, --notray Do not use a system tray icon (default).\n" + " -u, --update Force a running instance of ThunderPad to update its\n" " list of devices and layouts.\n" " \"layout name\" Load the given layout in an already running\n" - " instance of QJoyPad, or start QJoyPad using the\n" - " given layout.\n").arg(QJOYPAD_NAME, argc > 0 ? argv[0] : "qjoypad"))); + " instance of ThunderPad, or start ThunderPad using the\n" + " given layout.\n", + THUNDERPAD_NAME, argc > 0 ? argv[0] : "thunderpad"); return 0; case 'd': @@ -141,8 +115,8 @@ int main( int argc, char **argv ) devdir = optarg; } else { - errorBox(app.translate("main","Not a directory"), - app.translate("main","Path is not a directory: %1").arg(optarg)); + errorBox("Not a directory", + QString("Path is not a directory: %1").arg(optarg)); return 1; } break; @@ -161,9 +135,8 @@ int main( int argc, char **argv ) break; case '?': - fprintf(stderr, "%s", qPrintable(app.translate("main", - "Illeagal argument.\n" - "See `%1 --help` for more information\n").arg(argc > 0 ? argv[0] : "qjoypad"))); + fprintf(stderr, "Illegal argument.\n" + "See `%s --help` for more information\n", argc > 0 ? argv[0] : "thunderpad"); return 1; } } @@ -172,9 +145,8 @@ int main( int argc, char **argv ) layout = argv[optind ++]; if (optind < argc) { - fprintf(stderr, "%s", qPrintable(app.translate("main", - "Too many arguments.\n" - "See `%1 --help` for more information\n").arg(argc > 0 ? argv[0] : "qjoypad"))); + fprintf(stderr, "Too many arguments.\n" + "See `%s --help` for more information\n", argc > 0 ? argv[0] : "thunderpad"); return 1; } } @@ -197,8 +169,8 @@ int main( int argc, char **argv ) //create a pid lock file. - QFile pidFile( "/tmp/qjoypad.pid" ); - //if that file already exists, then qjoypad is already running! + QFile pidFile( "/tmp/thunderpad.pid" ); + //if that file already exists, then thunderpad is already running! if (pidFile.exists()) { int pid = 0; @@ -214,8 +186,8 @@ int main( int argc, char **argv ) //however, if we are setting the layout or updating the device //list, this is not an error and we shouldn't make one! if (layout.isEmpty() && !update) - errorBox(app.translate("main","Instance Error"), - app.translate("main","There is already a running instance of QJoyPad; please close\nthe old instance before starting a new one.")); + errorBox("Instance Error", + "There is already a running instance of ThunderPad; please close\nthe old instance before starting a new one."); else { //if one of these is the case, send the appropriate signal! if (update) { @@ -243,8 +215,8 @@ int main( int argc, char **argv ) sleep(1); sleepCounter++; if (sleepCounter > 20) { - errorBox(app.translate("main","System tray isn't loading"), - app.translate("main","Waited more than 20 seconds for the system tray to load. Giving up.")); + errorBox("System tray isn't loading", + "Waited more than 20 seconds for the system tray to load. Giving up."); return 1; } } diff --git a/src/quickset.h b/src/quickset.h index 99ff7a2..b6f2b19 100644 --- a/src/quickset.h +++ b/src/quickset.h @@ -1,5 +1,5 @@ -#ifndef QJOYPAD_QUICKSET_H -#define QJOYPAD_QUICKSET_H +#ifndef THUNDERPAD_QUICKSET_H +#define THUNDERPAD_QUICKSET_H //for building the dialog #include diff --git a/thunderpad.desktop b/thunderpad.desktop new file mode 100755 index 0000000..abe2041 --- /dev/null +++ b/thunderpad.desktop @@ -0,0 +1,9 @@ +[Desktop Entry] +Name=ThunderPad +GenericName=Accessible Joypad to Keyboard/Mouse Mapper +Exec=thunderpad +Icon=thunderpad +Type=Application +Terminal=false +Categories=Qt;Game;Accessibility; +Comment=Accessible joystick/gamepad configuration tool that maps controller inputs to keyboard and mouse events. diff --git a/translations/qjoypad_de.ts b/translations/qjoypad_de.ts deleted file mode 100644 index 5a39520..0000000 --- a/translations/qjoypad_de.ts +++ /dev/null @@ -1,667 +0,0 @@ - - - - - Axis - - - Axis %1 - Achse %1 - - - - KEYBOARD/MOUSE - TASTATUR/MAUS - - - - - MOUSE - MAUS - - - - KEYBOARD - TASTATUR - - - - THROTTLE - Drossel - - - - AxisEdit - - - &Gradient - &Verlauf - - - - Keyboard/Mouse Button - Tastatur-/Maus-Taste - - - - Mouse (Vert.) - Maus (Vert.) - - - - Mouse (Vert. Rev.) - Maus (Vert. Inv.) - - - - Mouse (Hor.) - Maus (Hor.) - - - - Mouse (Hor. Rev.) - Maus (Hor. Inv.) - - - - Linear - Linear - - - - Quadratic - Quadratisch - - - - Cubic - Cubisch - - - - Quadratic Extreme - Quadratisches Extrem - - - - Power Function - Potenzfunktion - - - - &Mouse Speed - &Mausgeschwindigkeit - - - - &Sensitivity - &Sensibilität - - - - Neg. Throttle - Neg. Drossel - - - - No Throttle - Keine Drossel - - - - Pos. Throttle - Pos. Drossel - - - - Button - - - Button %1 - Taste %1 - - - - %1 : Mouse %2 - %1: Maus %2 - - - - %1 : %2 - %1: %2 - - - - ButtonEdit - - - Set %1 - Setze %1 - - - - &Sticky - &Klebrig - - - - &Rapid Fire - &Schnellfeuer - - - - FloatingIcon - - - %1 Floating Icon - %1 Schwebendes Symbol - - - - GetKey - - - Choose a key - Wähle eine Taste - - - - Choose a new key or mouse button for %1 - Whähle eine neue Taste oder einen neuen Mausknopf für %1 - - - - Choose a new key for %1 - Wähle eine neue Taste für %1 - - - - -(Ctrl-X for no key) - -(Ctrl-X für keine Taste) - - - - JoyPad - - - Joystick %1 (%2) - Joystick %1 (%2) - - - - - - - - Layout file error - Belegungsdatei-Fehler - - - - - Expected ':', found '%1'. - ';' erwartet, '%1' vorgefunden. - - - - Error reading Button %1 - Fehler beim Lesen der Taste %1 - - - - Error reading Axis %1 - Fehler beim Lesen der Achse %1 - - - - Error while reading layout. Unrecognized word: %1 - Fehler beim Lesen der Belegung. Unbekanntes Wort: %1 - - - - JoyPadWidget - - - Clear - Löschen - - - - Quick Set - Schnell Setzen - - - - KeyButton - - - - Mouse %1 - Maus %1 - - - - LayoutEdit - - - Add Layout - Belegung Hinzufügen - - - - Remove Layout - Belegung Entfernen - - - - &Rename - &Umbenennen - - - - Rename Layout - Belegung Umbenennen - - - - &Import - &Importieren - - - - E&xport - E&xportieren - - - - &Save - &Speichern - - - - Re&vert - &Zurücksetzen - - - - &Close Dialog - &Fenster Schließen - - - - &Quit - &Beenden - - - - [NO LAYOUT] - [KEINE BELEGUNG] - - - - LayoutManager - - - Update &Joystick Devices - &Joysticks Aktualisieren - - - - Update &Layout List - Be&legungsliste Aktualisieren - - - - &Quit - &Beenden - - - - UDev Error - UDev Fehler - - - - Error creating UDev monitor. QJoyPad will still work, but it won't automatically update the joypad device list. - Fehler beim Erzeugen des UDev Monitors. QJoypad wird dennoch funktionieren, aber es wird nicht automatisch die Joypad-Liste aktualisieren. - - - - - - - - - Load error - Lade-Fehler - - - - Failed to find a layout named %1. - Belegung mit Namen %1 wurde nicht gefunden. - - - - Error reading from file: %1 - Fehler beim lesen der Datei: %1 - - - - Error reading joystick definition. Unexpected token "%1". Expected a positive number. - Fehler beim Lesen der Joystick-Definition. Unerwartets Token "%1". Eine positive Zahl wurde erwartet. - - - - Error reading joystick definition. Unexpected character "%1". Expected '{'. - Fehler beim Lesen der Joystick-Definition. Unerwartets Zeichen "%1". '{' wurde erwartet. - - - - Error reading definition for joystick %1. - Fehler beim Lesen der Definition von Joystick %1. - - - - Error reading joystick definition. Unexpected token "%1". Expected "Joystick". - Fehler beim Lesen der Joystick-Definition. Unerwartetes Token "%1". "Joystick" wurde erwertet. - - - - - - - Save error - Fehler beim Speichern - - - - Could not open file %1, layout not saved. - Konnte Datei %1 nicht öffnen, Belegung wurde nicht gespeichert. - - - - Name new layout - %1 - Neue Belegung benennen - %1 - - - - Import layout - %1 - Belegung Importieren - %1 - - - - - QJoyPad layout files (*.lyt) - QJoyPad Belegung-Dateien (*.lyt) - - - - - Any files (*) - Alle Dateien (*) - - - - Import error - Fehler beim Importieren - - - - Cannot import file from QJoyPad settings directory. - Kann Datei aus dem QJoyPad Einstellungsverzeichnis nicht importieren. - - - - Layout exists - Belegung existiert - - - - Layout %1 exists. Do you want to overwrite it? - Belegung %1 existiert. Wollen Sie sie überschreiben? - - - - Over&write - Über&schreiben - - - - - &Cancel - &Abbrechen - - - - Export layout - %1 - Belegung Exportieren - %1 - - - - Delete layout? - %1 - Belegung löschen? - %1 - - - - &Delete - &Löschen - - - - Enter a name for the new layout: - Name der neuen Belegung eingeben: - - - - - Layout name cannot be empty. - Belegungsname kann nicht leer sein. - - - - - Layout name may not contain a '/' (slash). - Belegungsname kann keinen '/' (Schrägstrich) enthalten. - - - - That name's already taken! - Dieser Name ist bereits belegt! - - - - Remove layout %1 permanently from your hard drive? - Belegung %1 permanent von ihrer Festplatte löschen? - - - - Remove error - Fehler beim Entfernen - - - - Could not remove file %1 - Konnte Datei %1 nicht entfernen - - - - Rename layout - %1 - Belegung umbenennen - %1 - - - - Enter a new name for the layout: - Geben Sie einen neuen Belegungsnamen ein: - - - - - - - Rename error - Umbenennungsfehler - - - - Layout with name %1 already exists. - Belegung mit dem Namen %1 existiert bereits. - - - - Error renaming layout. - Fehler beim Umbenennen einer Belegung. - - - - No joystick devices available - Keine Joysticks verfügbar - - - - No joystick devices are currently available to configure. -Please plug in a gaming device and select -"Update Joystick Devices" from the popup menu. - Zur Zeit sind keine Joysticks zur Konfiguration verfügbar. -Bitte schließen Sie ein entsprechendes Gerät an und -wählen Sie "Joysticks Aktualisieren" im Popup-Menü. - - - - [NO LAYOUT] - [KEINE BELEGUNG] - - - - QuickSet - - - Set %1 - Setze %1 - - - - Press any button or axis and -you will be prompted for a key. - Drücken sie eine belibige Taste oder Achse und -Sie werden nach einer Taste gefragt werden. - - - - Done - Fertig - - - - %1, positive - %1, positiv - - - - %1, negative - %1, negativ - - - - main - - - Couldn't create the QJoyPad save directory - Konnte das QJoyPad Seicher-Verzeichnis nicht anlegen - - - - Couldn't create the QJoyPad save directory: %s - Konnte das QJoyPad Seicher-Verzeichnis nicht anlegen: %s - - - - %1 -Usage: %2 [--device="/device/path"] [--notray|--force-tray] ["layout name"] - -Options: - -h, --help Print this help message. - -d, --device=PATH Look for joystick devices in PATH. This should - be something like "/dev/input" if your game - devices are in /dev/input/js0, /dev/input/js1, etc. - -t, --force-tray Force to use a system tray icon. - -T, --notray Do not use a system tray icon. This is useful for - window managers that don't support this feature. - -u, --update Force a running instance of QJoyPad to update its - list of devices and layouts. - "layout name" Load the given layout in an already running - instance of QJoyPad, or start QJoyPad using the - given layout. - - %1 -Verwendung: %2 [--device="/Geräte/Pfad"] [--notray|--force-tray] ["Belegungsname"] - -Optionen: - -h, --help Gibt diesen Hilfetext aus. - -d, --device=PFAD In PFAD nach Joystick-Geräten suchen. Dies sollte - "/dev/input" sein wenn Ihre Joysticks - /dev/input/js0, /dev/input/js1 etc. sind. - -t, --force-tray Verwendung der Systemablage erzwingen. - -T, --notray Systemablage nicht verwenden. Nützlich für - Fenstermanager die keine Systemablage unterstützen. - -u, --update Zwinge eine laufende Instanz von QJoyPad die - Geräte- und Belegungslisten zu aktualisieren. - "Belegungsname" Lade die angegebenen Belegung in einer bereits laufenden - Instanz von QJoyPad oder starte QJoyPad mit der gegebenen - Belegung. - - - - - - Not a directory - Kein Verzeichnis - - - - Path is not a directory: %1 - Pfad ist kein Verzeichnis: %1 - - - - Illeagal argument. -See `%1 --help` for more information - - Ungülltiges Argument. -Siehe `%1 --help` für mehr Information - - - - - Too many arguments. -See `%1 --help` for more information - - Zu viele Argumente. -Siehe `%1 --help` für mehr Information - - - - - Instance Error - Instanzierungs-Fehler - - - - There is already a running instance of QJoyPad; please close -the old instance before starting a new one. - Es läuft bereits eine Instanz von QJoyPad; bitte schließen -sie die alte Instanz bevor sie eine neue öffnen. - - - - System tray isn't loading - Systemablage startet nicht - - - - Waited more than 20 seconds for the system tray to load. Giving up. - Es wurde mehr als 20 Sekunden auf die Systemablage gewartet. Gebe auf. - - - diff --git a/translations/qjoypad_nl.ts b/translations/qjoypad_nl.ts deleted file mode 100644 index e4cd4f6..0000000 --- a/translations/qjoypad_nl.ts +++ /dev/null @@ -1,666 +0,0 @@ - - - - - Axis - - - Axis %1 - As %1 - - - - KEYBOARD/MOUSE - TOETSENBORD/MUIS - - - - - MOUSE - MUIS - - - - KEYBOARD - TOETSENBORD - - - - THROTTLE - BEPERKEN - - - - AxisEdit - - - &Gradient - &Verloop - - - - Keyboard/Mouse Button - Toetsenbord-/muisknop - - - - Mouse (Vert.) - Muis (vert.) - - - - Mouse (Vert. Rev.) - Muis (vert. omgekeerd) - - - - Mouse (Hor.) - Muis (hor.) - - - - Mouse (Hor. Rev.) - Muis (hor. omgekeerd) - - - - Linear - Linear - - - - Quadratic - Quadratisch - - - - Cubic - Cubisch - - - - Quadratic Extreme - Quadratisch (extreem) - - - - Power Function - Energiefunctie - - - - &Mouse Speed - &Muissnelheid - - - - &Sensitivity - &Gevoeligheid - - - - Neg. Throttle - Neg. beperking - - - - No Throttle - Geen beperking - - - - Pos. Throttle - Pos. beperking - - - - Button - - - Button %1 - Knop %1 - - - - %1 : Mouse %2 - %1: Muis %2 - - - - %1 : %2 - %1: %2 - - - - ButtonEdit - - - Set %1 - %1 instellen - - - - &Sticky - Plaktoet&s - - - - &Rapid Fire - &Snelvuren - - - - FloatingIcon - - - %1 Floating Icon - %1 zwevend pictogram - - - - GetKey - - - Choose a key - Kies een toets - - - - Choose a new key or mouse button for %1 - Kies een toets of muisknop voor %1 - - - - Choose a new key for %1 - Kies een toets voor %1 - - - - -(Ctrl-X for no key) - -(Ctrl-X om geen toets te gebruiken) - - - - JoyPad - - - Joystick %1 (%2) - Joystick %1 (%2) - - - - - - - - Layout file error - Fout in indelingsbestand - - - - - Expected ':', found '%1'. - ';' verwacht; '%1' aangetroffen. - - - - Error reading Button %1 - Fout tijdens uitlezen van knop %1 - - - - Error reading Axis %1 - Fout tijdens uitlezen van as %1 - - - - Error while reading layout. Unrecognized word: %1 - Fout tijdens uitlezen van indeling. Onbekend woord: %1 - - - - JoyPadWidget - - - Clear - Wissen - - - - Quick Set - Snel instellen - - - - KeyButton - - - - Mouse %1 - Muis %1 - - - - LayoutEdit - - - Add Layout - Indeling toevoegen - - - - Remove Layout - Indeling verwijderen - - - - &Rename - &Naam wijzigen - - - - Rename Layout - Indelingsnaam wijzigen - - - - &Import - &Importeren - - - - E&xport - E&xporteren - - - - &Save - Op&slaan - - - - Re&vert - &Terugdraaien - - - - &Close Dialog - &Venster sluiten - - - - &Quit - &Afsluiten - - - - [NO LAYOUT] - [GEEN INDELING] - - - - LayoutManager - - - Update &Joystick Devices - Zoeken naar &joysticks - - - - Update &Layout List - Inde&lingslijst verversen - - - - &Quit - &Afsluiten - - - - UDev Error - UDev-fout - - - - Error creating UDev monitor. QJoyPad will still work, but it won't automatically update the joypad device list. - Fout tijdens creëren van UDev-monitor. QJoypad werkt nog steeds, maar de joypadlijst wordt niet automatisch bijgewerkt. - - - - - - - - - Load error - Fout tijdens laden - - - - Failed to find a layout named %1. - Geen indeling aangetroffen met de naam '%1'. - - - - Error reading from file: %1 - Fout tijdens uitlezen van bestand: %1 - - - - Error reading joystick definition. Unexpected token "%1". Expected a positive number. - Fout tijdens uitlezen van joystick-definitie. Onverwachte sleutel '%1'. Er had een positief getal moeten staan. - - - - Error reading joystick definition. Unexpected character "%1". Expected '{'. - Fout tijdens uitlezen van joystick-definitie. Onverwacht teken '%1'. Er had '{' moeten staan. - - - - Error reading definition for joystick %1. - Fout tijdens uitlezen van joystick-definitie '%1'. - - - - Error reading joystick definition. Unexpected token "%1". Expected "Joystick". - Fout tijdens uitlezen van joystick-definitie. Onverwachte sleutel '%1'. Er had 'Joystick' moeten staan. - - - - - - - Save error - Fout tijdens opslaan - - - - Could not open file %1, layout not saved. - Kan '%1' niet openen; de indeling is niet opgeslagen. - - - - Name new layout - %1 - Geef de indeling een nieuwe naam - %1 - - - - Import layout - %1 - Indeling importeren - %1 - - - - - QJoyPad layout files (*.lyt) - QJoyPad-indelingsbestanden (*.lyt) - - - - - Any files (*) - Alle bestanden (*) - - - - Import error - Fout tijdens importeren - - - - Cannot import file from QJoyPad settings directory. - Kan het bestand uit de QJoyPad-instellingenmap niet importeren. - - - - Layout exists - Indeling bestaat al - - - - Layout %1 exists. Do you want to overwrite it? - De indeling '%1' bestaat al. Wil je deze overschrijven? - - - - Over&write - Over&schrijven - - - - - &Cancel - &Annuleren - - - - Export layout - %1 - Indeling exporteren - %1 - - - - Delete layout? - %1 - Wil je de indeling verwijderen? - %1 - - - - &Delete - Verwij&deren - - - - Enter a name for the new layout: - Voer een naam in voor de nieuwe indeling: - - - - - Layout name cannot be empty. - De indeling moet een naam hebben. - - - - - Layout name may not contain a '/' (slash). - De naam mag geen '/' (schuine streep) bevatten. - - - - That name's already taken! - Die naam is al in gebruik! - - - - Remove layout %1 permanently from your hard drive? - Wil je de indeling '%1' permanent van je computer verwijderen? - - - - Remove error - Fout tijdens verwijderen - - - - Could not remove file %1 - Kan '%1' niet verwijderen - - - - Rename layout - %1 - Indelingsnaam wijzigen - %1 - - - - Enter a new name for the layout: - Voer een naam in voor de indeling: - - - - - - - Rename error - Fout tijdens naamswijziging - - - - Layout with name %1 already exists. - Er bestaat al een indeling genaamd '%1'. - - - - Error renaming layout. - Fout tijdens naamswijziging. - - - - No joystick devices available - Geen joysticks beschikbaar - - - - No joystick devices are currently available to configure. -Please plug in a gaming device and select -"Update Joystick Devices" from the popup menu. - Er zijn geen in te stellen joysticks beschikbaar. -Koppel een apparaat aan en kies -"Zoeken naar joysticks" in het pop-upmenu. - - - - [NO LAYOUT] - [GEEN INDELING] - - - - QuickSet - - - Set %1 - %1 instellen - - - - Press any button or axis and -you will be prompted for a key. - Druk op een knop of as om -gevraagd te worden om een toets. - - - - Done - Klaar - - - - %1, positive - %1, positief - - - - %1, negative - %1, negatief - - - - main - - - Couldn't create the QJoyPad save directory - Kan geen map creëren voor het opslaan van QJoyPad-instellingen - - - - Couldn't create the QJoyPad save directory: %s - Kan geen map creëren voor het opslaan van QJoyPad-instellingen: %s - - - - %1 -Usage: %2 [--device="/device/path"] [--notray|--force-tray] ["layout name"] - -Options: - -h, --help Print this help message. - -d, --device=PATH Look for joystick devices in PATH. This should - be something like "/dev/input" if your game - devices are in /dev/input/js0, /dev/input/js1, etc. - -t, --force-tray Force to use a system tray icon. - -T, --notray Do not use a system tray icon. This is useful for - window managers that don't support this feature. - -u, --update Force a running instance of QJoyPad to update its - list of devices and layouts. - "layout name" Load the given layout in an already running - instance of QJoyPad, or start QJoyPad using the - given layout. - - %1 -Gebruik: %2 [--device="/Apparaat/Pad"] [--notray|--force-tray] ["Indelingsnaam"] - -Opties: - -h, --help Toont deze hulptekst. - -d, --device=PAD Zoek naar joysticks in het opgegeven pad. Dit moet zoiets als - "/dev/input" zijn als je joysticks in - /dev/input/js0, /dev/input/js1 staan. - -t, --force-tray Systeemvakpictogram afdwingen. - -T, --notray Geen systeemvakpictogram gebruiken. Dit is nuttig - als je vensterbeheerder hier geen ondersteuning voor heeft. - -u, --update Werk de apparaatlijst -en indeling bij van een actief - QJoyPad-proces. - "indelingsnaam" Laad de opgegeven indeling in een actief - QJoyPad-proces of start QJoyPad met de opgegeven - indeling. - - - - - Not a directory - Is geen map - - - - Path is not a directory: %1 - Het pad is geen map: %1 - - - - Illeagal argument. -See `%1 --help` for more information - - Ongeldig argument. -Bekijk `%1 --help` voor meer informatie - - - - - Too many arguments. -See `%1 --help` for more information - - Te veel argumenten. -Bekijk `%1 --help` voor meer informatie - - - - - Instance Error - Procesfout - - - - There is already a running instance of QJoyPad; please close -the old instance before starting a new one. - Er draait al een proces van QJoyPad. Breek het andere proces -af voordat je een nieuw proces start. - - - - System tray isn't loading - Systeemvak laad niet - - - - Waited more than 20 seconds for the system tray to load. Giving up. - Er is meer dan 20 seconden gewacht op het systeemvak. Actie afgebroken. - - -