Initial commit.

This commit is contained in:
Storm Dragon
2025-06-30 15:46:18 -04:00
parent 0390943fc5
commit 0b6f76a2b2
37 changed files with 955 additions and 2250 deletions

54
.gitignore vendored
View File

@ -1,4 +1,52 @@
.* # Build directories
build build/
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
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

294
CLAUDE.md Normal file
View File

@ -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.

View File

@ -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(THUNDERPAD_MAJOR 2025)
set(QJOYPAD_MINOR 3) set(THUNDERPAD_MINOR 06)
set(QJOYPAD_PATCH 0) set(THUNDERPAD_PATCH 30)
find_package(Qt5Widgets REQUIRED) find_package(Qt5Widgets REQUIRED)
find_package(Qt5LinguistTools REQUIRED)
find_package(Qt5X11Extras REQUIRED) find_package(Qt5X11Extras REQUIRED)
option(WITH_LIBUDEV "Use libudev for automatically updating joypad devices." ON) option(WITH_LIBUDEV "Use libudev for automatically updating joypad devices." ON)
@ -25,12 +24,10 @@ if(WITH_LIBUDEV)
include_directories(${LIBUDEV_INCLUDE_DIRS}) include_directories(${LIBUDEV_INCLUDE_DIRS})
endif() 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}") 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 # for config.h
include_directories("${PROJECT_BINARY_DIR}/src") 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(icons)
add_subdirectory(src) add_subdirectory(src)
add_custom_target(translations_target DEPENDS ${qjoypad_TRANS}) install(PROGRAMS thunderpad.desktop DESTINATION "share/applications")
add_dependencies(qjoypad translations_target)
install(PROGRAMS qjoypad.desktop DESTINATION "share/applications")
install(FILES ${qjoypad_TRANS} DESTINATION "share/qjoypad/translations")
# uninstall target # uninstall target
configure_file( configure_file(

863
README.md

File diff suppressed because it is too large Load Diff

View File

@ -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.

View File

@ -2,7 +2,7 @@ include(GenerateExportHeader)
configure_file(config.h.in "${CMAKE_CURRENT_BINARY_DIR}/config.h" @ONLY) configure_file(config.h.in "${CMAKE_CURRENT_BINARY_DIR}/config.h" @ONLY)
set(qjoypad_SOURCES set(thunderpad_SOURCES
axis.cpp axis.cpp
axis_edit.cpp axis_edit.cpp
axisw.cpp axisw.cpp
@ -22,7 +22,7 @@ set(qjoypad_SOURCES
main.cpp main.cpp
quickset.cpp) quickset.cpp)
set(qjoypad_QOBJECT_HEADERS set(thunderpad_QOBJECT_HEADERS
axis_edit.h axis_edit.h
axis.h axis.h
axisw.h axisw.h
@ -40,8 +40,8 @@ set(qjoypad_QOBJECT_HEADERS
layout.h layout.h
quickset.h) quickset.h)
qt5_wrap_cpp(qjoypad_HEADERS_MOC ${qjoypad_QOBJECT_HEADERS}) qt5_wrap_cpp(thunderpad_HEADERS_MOC ${thunderpad_QOBJECT_HEADERS})
add_executable(qjoypad ${qjoypad_SOURCES} ${qjoypad_HEADERS_MOC}) add_executable(thunderpad ${thunderpad_SOURCES} ${thunderpad_HEADERS_MOC})
target_link_libraries(qjoypad Qt5::Widgets Qt5::X11Extras Xtst X11 ${LIBUDEV_LIBRARIES}) target_link_libraries(thunderpad Qt5::Widgets Qt5::X11Extras Xtst X11 ${LIBUDEV_LIBRARIES})
install(TARGETS qjoypad RUNTIME DESTINATION "bin") install(TARGETS thunderpad RUNTIME DESTINATION "bin")

View File

@ -1,5 +1,5 @@
#ifndef QJOYPAD_AXIS_H #ifndef THUNDERPAD_AXIS_H
#define QJOYPAD_AXIS_H #define THUNDERPAD_AXIS_H
//abs() //abs()
#include <stdlib.h> #include <stdlib.h>

View File

@ -7,7 +7,7 @@ AxisEdit::AxisEdit( Axis* ax )
//build the dialog, display current axis settings :) //build the dialog, display current axis settings :)
axis = ax; axis = ax;
setWindowTitle("Set " + axis->getName()); 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 //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 //various layouts as the dialog is built and are not pointing to the same

View File

@ -1,5 +1,5 @@
#ifndef QJOYPAD_AXIS_EDIT_H #ifndef THUNDERPAD_AXIS_EDIT_H
#define QJOYPAD_AXIS_EDIT_H #define THUNDERPAD_AXIS_EDIT_H
//to refer to the axis we're editing //to refer to the axis we're editing
//for building up the dialog we need //for building up the dialog we need
#include "axis.h" #include "axis.h"

View File

@ -23,6 +23,13 @@ void AxisWidget::update() {
} }
void AxisWidget::mouseReleaseEvent( QMouseEvent* e ) { 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, //create the edit dialog,
ae = new AxisEdit(axis); ae = new AxisEdit(axis);
//get its input //get its input
@ -32,7 +39,4 @@ void AxisWidget::mouseReleaseEvent( QMouseEvent* e ) {
//and remember that it's gone. //and remember that it's gone.
ae = NULL; ae = NULL;
update(); 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 );
} }

View File

@ -1,5 +1,5 @@
#ifndef QJOYPAD_AXIS_WIDGET_H #ifndef THUNDERPAD_AXIS_WIDGET_H
#define QJOYPAD_AXIS_WIDGET_H #define THUNDERPAD_AXIS_WIDGET_H
#include <QMouseEvent> #include <QMouseEvent>
//so we can interact with the axis this refers to //so we can interact with the axis this refers to
@ -19,6 +19,8 @@ class AxisWidget : public FlashButton {
void jsevent( int val ); void jsevent( int val );
//change the text on this button to reflect the axis' current state. //change the text on this button to reflect the axis' current state.
void update(); void update();
//public method to configure this axis (for accessibility)
void configure();
private: private:
//to deal with clicking (by creating an AxisEdit dialog) //to deal with clicking (by creating an AxisEdit dialog)
void mouseReleaseEvent( QMouseEvent* e ); void mouseReleaseEvent( QMouseEvent* e );

View File

@ -1,5 +1,5 @@
#ifndef QJOYPAD_BUTTON_H #ifndef THUNDERPAD_BUTTON_H
#define QJOYPAD_BUTTON_H #define THUNDERPAD_BUTTON_H
#include <QTimer> #include <QTimer>
#include <QTextStream> #include <QTextStream>

View File

@ -10,7 +10,7 @@ ButtonEdit::ButtonEdit(Button* butt, const QStringList *layoutNames)
//build the dialog! //build the dialog!
button = butt; button = butt;
setWindowTitle(tr("Set %1").arg(button->getName())); setWindowTitle(tr("Set %1").arg(button->getName()));
setWindowIcon(QPixmap(QJOYPAD_ICON24)); setWindowIcon(QPixmap(THUNDERPAD_ICON24));
QVBoxLayout* v = new QVBoxLayout(this); QVBoxLayout* v = new QVBoxLayout(this);
v->setMargin(5); v->setMargin(5);

View File

@ -1,5 +1,5 @@
#ifndef QJOYPAD_BUTTON_EDIT_H #ifndef THUNDERPAD_BUTTON_EDIT_H
#define QJOYPAD_BUTTON_EDIT_H #define THUNDERPAD_BUTTON_EDIT_H
#include <QPushButton> #include <QPushButton>
#include <QCheckBox> #include <QCheckBox>

View File

@ -19,10 +19,13 @@ void ButtonWidget::update() {
} }
void ButtonWidget::mouseReleaseEvent( QMouseEvent* e ) { void ButtonWidget::mouseReleaseEvent( QMouseEvent* e ) {
configure();
FlashButton::mouseReleaseEvent( e );
}
void ButtonWidget::configure() {
ButtonEdit* be = new ButtonEdit(button, &layoutNames); ButtonEdit* be = new ButtonEdit(button, &layoutNames);
be->exec(); be->exec();
delete be; delete be;
update(); update();
FlashButton::mouseReleaseEvent( e );
} }

View File

@ -1,5 +1,5 @@
#ifndef QJOYPAD_BUTTON_WIDGET_H #ifndef THUNDERPAD_BUTTON_WIDGET_H
#define QJOYPAD_BUTTON_WIDGET_H #define THUNDERPAD_BUTTON_WIDGET_H
//this represents a Button //this represents a Button
#include "button.h" #include "button.h"
@ -21,6 +21,8 @@ class ButtonWidget : public FlashButton {
void jsevent( int val ); void jsevent( int val );
//reset the label to match the respective Button's current state. //reset the label to match the respective Button's current state.
void update(); void update();
//public method to configure this button (for accessibility)
void configure();
QStringList layoutNames; QStringList layoutNames;
private: private:
void mouseReleaseEvent( QMouseEvent* e ); void mouseReleaseEvent( QMouseEvent* e );

View File

@ -1,17 +1,16 @@
#ifndef QJOYPAD_CONFIG_H_IN #ifndef THUNDERPAD_CONFIG_H_IN
#define QJOYPAD_CONFIG_H_IN #define THUNDERPAD_CONFIG_H_IN
#cmakedefine QJOYPAD_MAJOR #cmakedefine THUNDERPAD_MAJOR
#cmakedefine QJOYPAD_MINOR #cmakedefine THUNDERPAD_MINOR
#cmakedefine QJOYPAD_PATCH #cmakedefine THUNDERPAD_PATCH
#define QJOYPAD_VERSION "@QJOYPAD_MAJOR@.@QJOYPAD_MINOR@.@QJOYPAD_PATCH@" #define THUNDERPAD_VERSION "@THUNDERPAD_MAJOR@.@THUNDERPAD_MINOR@.@THUNDERPAD_PATCH@"
#define QJOYPAD_NAME "QJoyPad @QJOYPAD_MAJOR@.@QJOYPAD_MINOR@" #define THUNDERPAD_NAME "ThunderPad @THUNDERPAD_MAJOR@.@THUNDERPAD_MINOR@"
#define QJOYPAD_DEVDIR "@DEVICE_DIR@" #define THUNDERPAD_DEVDIR "@DEVICE_DIR@"
#define QJOYPAD_ICON24 "@CMAKE_INSTALL_PREFIX@/share/icons/hicolor/24x24/apps/qjoypad.png" #define THUNDERPAD_ICON24 "@CMAKE_INSTALL_PREFIX@/share/icons/hicolor/24x24/apps/thunderpad.png"
#define QJOYPAD_ICON64 "@CMAKE_INSTALL_PREFIX@/share/icons/hicolor/64x64/apps/qjoypad.png" #define THUNDERPAD_ICON64 "@CMAKE_INSTALL_PREFIX@/share/icons/hicolor/64x64/apps/thunderpad.png"
#define QJOYPAD_L10N_DIR "@CMAKE_INSTALL_PREFIX@/share/qjoypad/translations/"
#cmakedefine WITH_LIBUDEV #cmakedefine WITH_LIBUDEV

View File

@ -1,5 +1,5 @@
#ifndef QJOYPAD_CONSTANT_H #ifndef THUNDERPAD_CONSTANT_H
#define QJOYPAD_CONSTANT_H #define THUNDERPAD_CONSTANT_H
//How many cycles there are per click. //How many cycles there are per click.
#define FREQ 10 #define FREQ 10

View File

@ -1,5 +1,5 @@
#ifndef QJOYPAD_ERROR_H #ifndef THUNDERPAD_ERROR_H
#define QJOYPAD_ERROR_H #define THUNDERPAD_ERROR_H
#include <qmessagebox.h> #include <qmessagebox.h>
#include <stdarg.h> #include <stdarg.h>
@ -8,7 +8,7 @@
//a nice simple way of throwing up an error message if something goes wrong. //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) { 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); message, QMessageBox::Ok, Qt::NoButton);
} }

View File

@ -1,12 +1,12 @@
#ifndef QJOYPAD_EVENT_H #ifndef THUNDERPAD_EVENT_H
#define QJOYPAD_EVENT_H #define THUNDERPAD_EVENT_H
//for the functions we need to generate keypresses / mouse actions //for the functions we need to generate keypresses / mouse actions
#include <X11/extensions/XTest.h> #include <X11/extensions/XTest.h>
//a simplified event structure that can handle buttons and mouse movements //a simplified event structure that can handle buttons and mouse movements
struct FakeEvent { struct FakeEvent {
//types of events QJoyPad can create. //types of events ThunderPad can create.
//KeyRelease, KeyPress, ButtonRelease, ButtonPress, and MouseMove //KeyRelease, KeyPress, ButtonRelease, ButtonPress, and MouseMove
enum EventType {KeyUp, KeyDown, MouseUp, MouseDown, MouseMove, MouseMoveAbsolute}; enum EventType {KeyUp, KeyDown, MouseUp, MouseDown, MouseMove, MouseMoveAbsolute};

View File

@ -1,5 +1,5 @@
#ifndef QJOYPAD_FLASH_H #ifndef THUNDERPAD_FLASH_H
#define QJOYPAD_FLASH_H #define THUNDERPAD_FLASH_H
#include <QPushButton> #include <QPushButton>
#include <QPalette> #include <QPalette>

View File

@ -9,7 +9,7 @@ FloatingIcon::FloatingIcon( const QString &icon, QMenu *popup, QWidget *parent,
setAttribute(Qt::WA_QuitOnClose); setAttribute(Qt::WA_QuitOnClose);
setAttribute(Qt::WA_TranslucentBackground); setAttribute(Qt::WA_TranslucentBackground);
setWindowFlags(Qt::FramelessWindowHint); setWindowFlags(Qt::FramelessWindowHint);
setWindowTitle(tr("%1 Floating Icon").arg(QJOYPAD_NAME)); setWindowTitle(tr("%1 Floating Icon").arg(THUNDERPAD_NAME));
pop = popup; pop = popup;
setFixedSize(this->icon.width(),this->icon.height()); setFixedSize(this->icon.width(),this->icon.height());

View File

@ -1,5 +1,5 @@
#ifndef QJOYPAD_ICON_H #ifndef THUNDERPAD_ICON_H
#define QJOYPAD_ICON_H #define THUNDERPAD_ICON_H
#include <QDialog> #include <QDialog>
#include <QMenu> #include <QMenu>

View File

@ -1,5 +1,5 @@
#ifndef QJOYPAD_JOYPAD_H #ifndef THUNDERPAD_JOYPAD_H
#define QJOYPAD_JOYPAD_H #define THUNDERPAD_JOYPAD_H
//parts of the joypad //parts of the joypad
#include "button.h" #include "button.h"

View File

@ -2,46 +2,112 @@
JoyPadWidget::JoyPadWidget( JoyPad* jp, int i, QWidget* parent ) JoyPadWidget::JoyPadWidget( JoyPad* jp, int i, QWidget* parent )
: QWidget(parent) { : QWidget(parent) {
//initialize things, build the dialog //initialize things, build the accessible dialog
joypad = jp; joypad = jp;
index = i; 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; flashcount = 0;
int insertCounter = 0;
quickset = NULL; 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) { 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); axes.append(aw);
connect( aw, SIGNAL( flashed( bool ) ), this, SLOT( flash( bool ))); connect( aw, SIGNAL( flashed( bool ) ), this, SLOT( flash( bool )));
layoutMain->addWidget(aw, insertCounter / 2, insertCounter % 2);
insertCounter++;
} }
foreach (Button *button, joypad->buttons) { 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); buttons.append(bw);
connect( bw, SIGNAL( flashed( bool ) ), this, SLOT( flash( bool ))); connect( bw, SIGNAL( flashed( bool ) ), this, SLOT( flash( bool )));
layoutMain->addWidget(bw, insertCounter / 2, insertCounter % 2);
insertCounter++;
} }
if (insertCounter % 2 == 1) { // Control buttons
insertCounter ++; QHBoxLayout *controlLayout = new QHBoxLayout();
} btnClear = new QPushButton(QIcon::fromTheme("edit-clear"), "Clear All", this);
insertCounter += 2; btnClear->setAccessibleDescription("Clear all axis and button configurations");
btnClear = new QPushButton(QIcon::fromTheme("edit-clear"), tr("Clear"), this); btnClear->setFocusPolicy(Qt::StrongFocus);
btnClear->setAccessibleName("Clear All Button");
connect(btnClear, SIGNAL(clicked()), this, SLOT(clear())); connect(btnClear, SIGNAL(clicked()), this, SLOT(clear()));
layoutMain->addWidget(btnClear, insertCounter / 2, insertCounter % 2); controlLayout->addWidget(btnClear);
insertCounter++;
btnAll = new QPushButton(tr("Quick Set"), this); btnAll = new QPushButton("Quick Set", this);
layoutMain->addWidget(btnAll, insertCounter / 2, insertCounter % 2); 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())); 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() { JoyPadWidget::~JoyPadWidget() {
@ -63,12 +129,28 @@ void JoyPadWidget::flash( bool on ) {
} }
void JoyPadWidget::update() { void JoyPadWidget::update() {
// Update underlying widgets
foreach (AxisWidget *axis, axes) { foreach (AxisWidget *axis, axes) {
axis->update(); axis->update();
} }
foreach (ButtonWidget *button, buttons) { foreach (ButtonWidget *button, buttons) {
button->update(); 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() { void JoyPadWidget::clear() {
@ -109,3 +191,51 @@ void JoyPadWidget::updateButtonLayoutLists(const QStringList layoutNames) {
bw->layoutNames = layoutNames; 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");
}
}

View File

@ -1,10 +1,16 @@
#ifndef QJOYPAD_JOYPAD_WIDGET_H #ifndef THUNDERPAD_JOYPAD_WIDGET_H
#define QJOYPAD_JOYPAD_WIDGET_H #define THUNDERPAD_JOYPAD_WIDGET_H
//parts for the widget //parts for the widget
//Added by qt3to4: //Added by qt3to4:
#include <QList> #include <QList>
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QGroupBox>
#include <QListWidget>
#include <QPushButton>
#include <QLabel>
#include <linux/joystick.h> #include <linux/joystick.h>
#include "axisw.h" #include "axisw.h"
//this all relates to a JoyPad //this all relates to a JoyPad
@ -38,6 +44,11 @@ class JoyPadWidget : public QWidget {
void clear(); void clear();
//quickset! //quickset!
void setAll(); void setAll();
//accessible configuration slots
void configureSelectedAxis();
void configureSelectedButton();
void onAxisSelectionChanged();
void onButtonSelectionChanged();
signals: signals:
//happens whenever the tab that represents this joypadwidget should flash //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 //(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; int flashcount;
//the parts of the dialog //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<AxisWidget*> axes; QList<AxisWidget*> axes;
QList<ButtonWidget*> buttons; QList<ButtonWidget*> buttons;
QPushButton *btnClear, *btnAll;
//the quickset window, when we create it //the quickset window, when we create it
QuickSet* quickset; QuickSet* quickset;

View File

@ -1,5 +1,5 @@
#ifndef QJOYPAD_JOYSLIDER_H #ifndef THUNDERPAD_JOYSLIDER_H
#define QJOYPAD_JOYSLIDER_H #define THUNDERPAD_JOYSLIDER_H
//the parent of this //the parent of this

View File

@ -1,5 +1,5 @@
#ifndef QJOYPAD_KEYCODE_H #ifndef THUNDERPAD_KEYCODE_H
#define QJOYPAD_KEYCODE_H #define THUNDERPAD_KEYCODE_H
//To create the "press a key" dialog: //To create the "press a key" dialog:
#include <QPushButton> #include <QPushButton>

View File

@ -13,11 +13,11 @@
LayoutManager::LayoutManager( bool useTrayIcon, const QString &devdir, const QString &settingsDir ) LayoutManager::LayoutManager( bool useTrayIcon, const QString &devdir, const QString &settingsDir )
: devdir(devdir), settingsDir(settingsDir), : devdir(devdir), settingsDir(settingsDir),
layoutGroup(new QActionGroup(this)), layoutGroup(new QActionGroup(this)),
updateDevicesAction(new QAction(QIcon::fromTheme("view-refresh"),tr("Update &Joystick Devices"),this)), updateDevicesAction(new QAction(QIcon::fromTheme("view-refresh"),"Update &Joystick Devices",this)),
updateLayoutsAction(new QAction(QIcon::fromTheme("view-refresh"),tr("Update &Layout List"),this)), updateLayoutsAction(new QAction(QIcon::fromTheme("view-refresh"),"Update &Layout List",this)),
addNewConfiguration(new QAction(QIcon::fromTheme("list-add"),tr("Add new configuration"),this)), addNewConfiguration(new QAction(QIcon::fromTheme("list-add"),"Add new configuration",this)),
quitAction(new QAction(QIcon::fromTheme("application-exit"),tr("&Quit"),this)), quitAction(new QAction(QIcon::fromTheme("application-exit"),"&Quit",this)),
le(0) { le(0), isNotrayMode(!useTrayIcon) {
#ifdef WITH_LIBUDEV #ifdef WITH_LIBUDEV
udevNotifier = 0; udevNotifier = 0;
@ -25,8 +25,8 @@ LayoutManager::LayoutManager( bool useTrayIcon, const QString &devdir, const QSt
monitor = 0; monitor = 0;
if (!initUDev()) { if (!initUDev()) {
errorBox(tr("UDev Error"), tr("Error creating UDev monitor. " errorBox("UDev Error", "Error creating UDev monitor. "
"QJoyPad will still work, but it won't automatically update the joypad device list.")); "ThunderPad will still work, but it won't automatically update the joypad device list.");
} }
#endif #endif
@ -37,17 +37,14 @@ LayoutManager::LayoutManager( bool useTrayIcon, const QString &devdir, const QSt
if (useTrayIcon) { if (useTrayIcon) {
QSystemTrayIcon *tray = new QSystemTrayIcon(this); QSystemTrayIcon *tray = new QSystemTrayIcon(this);
tray->setContextMenu(&trayMenu); tray->setContextMenu(&trayMenu);
tray->setIcon(QIcon(QJOYPAD_ICON24)); tray->setIcon(QIcon(THUNDERPAD_ICON24));
tray->show(); tray->show();
connect(tray, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), this, SLOT(trayClick(QSystemTrayIcon::ActivationReason))); 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 { else {
FloatingIcon* icon = new FloatingIcon(QJOYPAD_ICON64,&trayMenu,0,"tray"); // Automatically show the configuration window for accessibility
connect(icon, SIGNAL(clicked()), this, SLOT(iconClick())); addNewConfig();
connect(icon, SIGNAL(rejected()), qApp, SLOT(quit()));
connect(icon, SIGNAL(accepted()), qApp, SLOT(quit()));
icon->show();
} }
connect(updateLayoutsAction, SIGNAL(triggered()), this, SLOT(fillPopup())); 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 it's good, start writing the file
if (file.open(QIODevice::WriteOnly)) { if (file.open(QIODevice::WriteOnly)) {
QTextStream stream( &file ); QTextStream stream( &file );
stream << "# " QJOYPAD_NAME " Layout File\n\n"; stream << "# " THUNDERPAD_NAME " Layout File\n\n";
foreach (JoyPad *joypad, joypads) { foreach (JoyPad *joypad, joypads) {
joypad->write( stream ); joypad->write( stream );
} }
@ -332,8 +329,8 @@ void LayoutManager::saveAs() {
bool ok = false; bool ok = false;
//request a new name! //request a new name!
QString name = QInputDialog::getText(le, QString name = QInputDialog::getText(le,
tr("Name new layout - %1").arg(QJOYPAD_NAME), QString("Name new layout - %1").arg(THUNDERPAD_NAME),
tr("Enter a name for the new layout:"), "Enter a name for the new layout:",
QLineEdit::Normal, QString(), &ok); QLineEdit::Normal, QString(), &ok);
if (!ok) { if (!ok) {
return; return;
@ -368,11 +365,11 @@ void LayoutManager::saveAs() {
void LayoutManager::importLayout() { void LayoutManager::importLayout() {
QFileDialog dialog(le); 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.setFileMode(QFileDialog::ExistingFile);
dialog.setAcceptMode(QFileDialog::AcceptOpen); dialog.setAcceptMode(QFileDialog::AcceptOpen);
QStringList filters; QStringList filters;
filters.append(tr("QJoyPad layout files (*.lyt)")); filters.append("ThunderPad layout files (*.lyt)");
filters.append(tr("Any files (*)")); filters.append(tr("Any files (*)"));
dialog.setNameFilters(filters); dialog.setNameFilters(filters);
dialog.setDefaultSuffix("lyt"); dialog.setDefaultSuffix("lyt");
@ -388,13 +385,13 @@ void LayoutManager::importLayout() {
QString filename = getFileName(layoutName); QString filename = getFileName(layoutName);
if (info == QFileInfo(filename)) { 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; return;
} }
if (QFile::exists(filename)) { if (QFile::exists(filename)) {
if (QMessageBox::warning(le, 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("Layout \"%1\" exists. Do you want to overwrite it?").arg(layoutName),
tr("Over&write"), tr("&Cancel"), QString(), 0, 1) == 1) { tr("Over&write"), tr("&Cancel"), QString(), 0, 1) == 1) {
return; return;
@ -414,11 +411,11 @@ void LayoutManager::importLayout() {
void LayoutManager::exportLayout() { void LayoutManager::exportLayout() {
QFileDialog dialog(le); 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.setFileMode(QFileDialog::AnyFile);
dialog.setAcceptMode(QFileDialog::AcceptSave); dialog.setAcceptMode(QFileDialog::AcceptSave);
QStringList filters; QStringList filters;
filters.append(tr("QJoyPad layout files (*.lyt)")); filters.append("ThunderPad layout files (*.lyt)");
filters.append(tr("Any files (*)")); filters.append(tr("Any files (*)"));
dialog.setNameFilters(filters); dialog.setNameFilters(filters);
dialog.setDefaultSuffix("lyt"); dialog.setDefaultSuffix("lyt");
@ -437,7 +434,7 @@ void LayoutManager::saveDefault() {
void LayoutManager::remove() { void LayoutManager::remove() {
if (currentLayout.isNull()) return; 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) { tr("Remove layout %1 permanently from your hard drive?").arg(currentLayout), tr("&Delete"), tr("&Cancel"), QString(), 0, 1 ) == 1) {
return; return;
} }
@ -457,7 +454,7 @@ void LayoutManager::rename() {
if (currentLayout.isNull()) return; if (currentLayout.isNull()) return;
bool ok = false; bool ok = false;
QString name = QInputDialog::getText(le, 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:"), tr("Enter a new name for the layout:"),
QLineEdit::Normal, currentLayout, &ok); QLineEdit::Normal, currentLayout, &ok);
if (!ok) { if (!ok) {
@ -555,7 +552,7 @@ void LayoutManager::fillPopup() {
trayMenu.addSeparator(); trayMenu.addSeparator();
//add null layout //add null layout
QAction *action = trayMenu.addAction(tr("[NO LAYOUT]")); QAction *action = trayMenu.addAction("[NO LAYOUT]");
action->setCheckable(true); action->setCheckable(true);
action->setActionGroup(layoutGroup); action->setActionGroup(layoutGroup);
//put a check by the current one ;) //put a check by the current one ;)
@ -683,6 +680,11 @@ void LayoutManager::addNewConfig() {
// make a new LayoutEdit dialog and show it. // make a new LayoutEdit dialog and show it.
le = new LayoutEdit(this); le = new LayoutEdit(this);
le->setLayout(currentLayout); 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) {
if (le->isActiveWindow()) { if (le->isActiveWindow()) {

View File

@ -1,9 +1,9 @@
#ifndef QJOYPAD_LAYOUT_H #ifndef THUNDERPAD_LAYOUT_H
#define QJOYPAD_LAYOUT_H #define THUNDERPAD_LAYOUT_H
//to allow for interprocess communications (ie, signaling a running instance of //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 //triger certain events. This is for signaling the main program to update
//the joystick device list. //the joystick device list.
#include <signal.h> #include <signal.h>
@ -109,6 +109,7 @@ class LayoutManager : public QObject {
QHash<int, JoyPad*> available; QHash<int, JoyPad*> available;
QHash<int, JoyPad*> joypads; QHash<int, JoyPad*> joypads;
bool isNotrayMode;
#ifdef WITH_LIBUDEV #ifdef WITH_LIBUDEV
bool initUDev(); bool initUDev();

View File

@ -6,8 +6,7 @@ LayoutEdit::LayoutEdit( LayoutManager* l )
: QWidget(0), : QWidget(0),
lm(l), lm(l),
mainLayout(0), mainLayout(0),
padStack(0), joypadTabs(0),
joyButtons(0),
cmbLayouts(0), cmbLayouts(0),
btnAdd(0), btnAdd(0),
btnRem(0), btnRem(0),
@ -17,8 +16,8 @@ LayoutEdit::LayoutEdit( LayoutManager* l )
btnImport(0), btnImport(0),
btnRename(0) { btnRename(0) {
setAttribute(Qt::WA_DeleteOnClose); setAttribute(Qt::WA_DeleteOnClose);
setWindowTitle( QJOYPAD_NAME ); setWindowTitle( THUNDERPAD_NAME );
setWindowIcon(QPixmap(QJOYPAD_ICON64)); setWindowIcon(QPixmap(THUNDERPAD_ICON64));
mainLayout = new QVBoxLayout(this); mainLayout = new QVBoxLayout(this);
mainLayout->setSpacing(5); mainLayout->setSpacing(5);
@ -35,7 +34,7 @@ LayoutEdit::LayoutEdit( LayoutManager* l )
//most of these buttons can link directly into slots in the LayoutManager //most of these buttons can link directly into slots in the LayoutManager
btnAdd = new QPushButton(frame); btnAdd = new QPushButton(frame);
btnAdd->setIcon(QIcon::fromTheme("list-add")); btnAdd->setIcon(QIcon::fromTheme("list-add"));
btnAdd->setToolTip(tr("Add Layout")); btnAdd->setToolTip("Add Layout");
if (btnAdd->icon().isNull()) { if (btnAdd->icon().isNull()) {
btnAdd->setText("+"); btnAdd->setText("+");
} }
@ -47,12 +46,12 @@ LayoutEdit::LayoutEdit( LayoutManager* l )
if (btnRem->icon().isNull()) { if (btnRem->icon().isNull()) {
btnRem->setText("-"); btnRem->setText("-");
} }
btnRem->setToolTip(tr("Remove Layout")); btnRem->setToolTip("Remove Layout");
btnRem->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); btnRem->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
connect(btnRem, SIGNAL(clicked()), lm, SLOT(remove())); connect(btnRem, SIGNAL(clicked()), lm, SLOT(remove()));
btnRename = new QPushButton(tr("&Rename"), frame); btnRename = new QPushButton("&Rename", frame);
btnRename->setToolTip(tr("Rename Layout")); btnRename->setToolTip("Rename Layout");
btnRename->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); btnRename->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
connect(btnRename, SIGNAL(clicked()), lm, SLOT(rename())); connect(btnRename, SIGNAL(clicked()), lm, SLOT(rename()));
@ -63,64 +62,46 @@ LayoutEdit::LayoutEdit( LayoutManager* l )
layoutLayout->addWidget(btnRename); layoutLayout->addWidget(btnRename);
mainLayout->addLayout(layoutLayout); 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())); connect(btnImport, SIGNAL(clicked()), lm, SLOT(importLayout()));
g->addWidget(btnImport,1,0); 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())); connect(btnExport, SIGNAL(clicked()), lm, SLOT(exportLayout()));
g->addWidget(btnExport,1,1); 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())); connect(btnUpd, SIGNAL(clicked()), lm, SLOT(save()));
g->addWidget(btnUpd,1,2); 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())); connect(btnRev, SIGNAL(clicked()), lm, SLOT(reload()));
g->addWidget(btnRev,1,3); g->addWidget(btnRev,1,3);
mainLayout->addWidget( frame ); mainLayout->addWidget( frame );
//produce a list of names for the FlashRadioArray //create a tab widget for joystick devices - much more accessible
//this is only necesary since joystick devices need not always be joypadTabs = new QTabWidget(this);
//contiguous joypadTabs->setTabPosition(QTabWidget::North);
QStringList names; mainLayout->addWidget(joypadTabs);
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);
//go through each of the available joysticks //go through each of the available joysticks
// i is the current index into PadStack
int i = 0;
foreach (JoyPad *joypad, lm->available) { foreach (JoyPad *joypad, lm->available) {
//add a new JoyPadWidget to the stack connect(this, SIGNAL(focusStateChanged(bool)), joypad, SLOT(focusChange(bool)));
padStack->insertWidget( i, joypad->widget(padStack,i) ); //create accessible widget and add as tab
//every time it "flashes", flash the associated tab. QScrollArea *scroll = new QScrollArea();
connect( padStack->widget(i), SIGNAL( flashed( int ) ), joyButtons, SLOT( flash( int ))); scroll->setWidgetResizable(true);
++i; 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(); updateLayoutList();
//add the buttons at the bottom. //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())); 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())); connect( quit, SIGNAL( clicked() ), qApp, SLOT(quit()));
QHBoxLayout* h = new QHBoxLayout(); QHBoxLayout* h = new QHBoxLayout();
@ -150,15 +131,21 @@ void LayoutEdit::setLayout(const QString &layout) {
btnRename->setEnabled(hasLayout); btnRename->setEnabled(hasLayout);
//update all the JoyPadWidgets. //update all the JoyPadWidgets.
for (int i = 0, n = lm->available.count(); i < n; i++) { for (int i = 0; i < joypadTabs->count(); i++) {
((JoyPadWidget*)padStack->widget(i))->update(); QScrollArea *scroll = qobject_cast<QScrollArea*>(joypadTabs->widget(i));
if (scroll) {
JoyPadWidget *jpw = qobject_cast<JoyPadWidget*>(scroll->widget());
if (jpw) {
jpw->update();
}
}
} }
} }
void LayoutEdit::updateLayoutList() { void LayoutEdit::updateLayoutList() {
//blank the list, then load in new names from the LayoutManager. //blank the list, then load in new names from the LayoutManager.
cmbLayouts->clear(); cmbLayouts->clear();
cmbLayouts->addItem(tr("[NO LAYOUT]"), QVariant(QString())); cmbLayouts->addItem("[NO LAYOUT]", QVariant(QString()));
if (lm->currentLayout.isNull()) { if (lm->currentLayout.isNull()) {
cmbLayouts->setCurrentIndex(0); cmbLayouts->setCurrentIndex(0);
} }
@ -169,38 +156,35 @@ void LayoutEdit::updateLayoutList() {
} }
} }
//Update layout list for all button edit widgets //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(); const QStringList layoutNames = lm->getLayoutNames();
((JoyPadWidget*)padStack->widget(i))->updateButtonLayoutLists(layoutNames); QScrollArea *scroll = qobject_cast<QScrollArea*>(joypadTabs->widget(i));
if (scroll) {
JoyPadWidget *jpw = qobject_cast<JoyPadWidget*>(scroll->widget());
if (jpw) {
jpw->updateButtonLayoutLists(layoutNames);
}
}
} }
} }
void LayoutEdit::updateJoypadWidgets() { void LayoutEdit::updateJoypadWidgets() {
int indexOfFlashRadio = mainLayout->indexOf(joyButtons); // Clear existing tabs
FlashRadioArray *newJoyButtons; while (joypadTabs->count() > 0) {
QStringList names; QWidget *widget = joypadTabs->widget(0);
foreach (JoyPad *joypad, lm->available) { joypadTabs->removeTab(0);
names.append(joypad->getName()); widget->deleteLater();
} }
newJoyButtons = new FlashRadioArray( names, true, this ); // Add tabs for each available joypad
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; i<numberOfJoypads; i++) {
padStack->removeWidget(padStack->widget(0));
}
int i = 0;
foreach (JoyPad *joypad, lm->available) { foreach (JoyPad *joypad, lm->available) {
//add a new JoyPadWidget to the stack connect(this, SIGNAL(focusStateChanged(bool)), joypad, SLOT(focusChange(bool)));
padStack->insertWidget( i, joypad->widget(padStack,i) ); // Create accessible widget and add as tab
//every time it "flashes", flash the associated tab. QScrollArea *scroll = new QScrollArea();
connect( padStack->widget(i), SIGNAL( flashed( int ) ), joyButtons, SLOT( flash( int ))); scroll->setWidgetResizable(true);
++i; JoyPadWidget *widget = joypad->widget(scroll, joypad->getIndex());
scroll->setWidget(widget);
joypadTabs->addTab(scroll, joypad->getName());
} }
} }

View File

@ -1,11 +1,8 @@
#ifndef QJOYPAD_LAYOUT_EDIT_H #ifndef THUNDERPAD_LAYOUT_EDIT_H
#define QJOYPAD_LAYOUT_EDIT_H #define THUNDERPAD_LAYOUT_EDIT_H
#include <QScrollArea> #include <QScrollArea>
#include <QStackedWidget> #include <QTabWidget>
//for the tab list of joypads
#include "flash.h"
//this is a front end for the non-GUI LayoutManager //this is a front end for the non-GUI LayoutManager
class LayoutEdit; class LayoutEdit;
#include "layout.h" #include "layout.h"
@ -34,9 +31,7 @@ class LayoutEdit : public QWidget {
LayoutManager* lm; LayoutManager* lm;
//parts of the dialog: //parts of the dialog:
QVBoxLayout *mainLayout; QVBoxLayout *mainLayout;
QScrollArea *padScroll; QTabWidget *joypadTabs;
QStackedWidget *padStack;
FlashRadioArray *joyButtons;
QComboBox* cmbLayouts; QComboBox* cmbLayouts;
QPushButton *btnAdd, *btnRem, *btnUpd, *btnRev, *btnExport, *btnImport, *btnRename; QPushButton *btnAdd, *btnRem, *btnUpd, *btnRev, *btnExport, *btnImport, *btnRename;
}; };

View File

@ -10,7 +10,6 @@
#include <QSystemTrayIcon> #include <QSystemTrayIcon>
#include <QPointer> #include <QPointer>
#include <QFileInfo> #include <QFileInfo>
#include <QTranslator>
//to load layouts //to load layouts
#include "layout.h" #include "layout.h"
@ -25,7 +24,7 @@ QPointer<LayoutManager> layoutManagerPtr;
//signal handler for SIGUSR2 //signal handler for SIGUSR2
//SIGUSR2 means that a new layout should be loaded. It is saved in //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 ) { void catchSIGUSR2( int sig ) {
if (layoutManagerPtr) layoutManagerPtr->load(); if (layoutManagerPtr) layoutManagerPtr->load();
//remember to catch this signal again next time. //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 //create a new event loop. This will be captured by the QApplication
//when it gets created //when it gets created
QApplication app( argc, argv ); QApplication app( argc, argv );
QTranslator translator;
app.setQuitOnLastWindowClosed(false); app.setQuitOnLastWindowClosed(false);
if (translator.load(QLocale::system(), "qjoypad", "_", QJOYPAD_L10N_DIR)) { //where ThunderPad saves its settings!
app.installTranslator(&translator); const QString settingsDir(QDir::homePath() + "/.config/thunderpad/");
}
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 to look for settings. If it does not exist, it will be created //where to look for settings. If it does not exist, it will be created
QDir dir(settingsDir); 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") //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 there is no new directory and we can't make it, complain
if (!dir.exists() && !dir.mkdir(settingsDir)) { if (!dir.exists() && !dir.mkdir(settingsDir)) {
errorBox(app.translate("main","Couldn't create the QJoyPad save directory"), errorBox("Couldn't create the ThunderPad save directory",
app.translate("main","Couldn't create the QJoyPad save directory: %1").arg(settingsDir)); QString("Couldn't create the ThunderPad save directory: %1").arg(settingsDir));
return 1; return 1;
} }
//start out with no special layout. //start out with no special layout.
QString layout; QString layout;
//by default, we use a tray icon //by default, we do NOT use a tray icon (more accessible)
bool useTrayIcon = true; bool useTrayIcon = false;
//this execution wasn't made to update the joystick device list. //this execution wasn't made to update the joystick device list.
bool update = false; bool update = false;
bool forceTrayIcon = false; bool forceTrayIcon = false;
@ -104,7 +78,7 @@ int main( int argc, char **argv )
struct option long_options[] = { struct option long_options[] = {
{"help", no_argument, 0, 'h'}, {"help", no_argument, 0, 'h'},
{"device", required_argument, 0, 'd'}, {"device", required_argument, 0, 'd'},
{"force-tray", no_argument, 0, 't'}, {"tray", no_argument, 0, 't'},
{"notray", no_argument, 0, 'T'}, {"notray", no_argument, 0, 'T'},
{"update", no_argument, 0, 'u'}, {"update", no_argument, 0, 'u'},
{0, 0, 0, 0 } {0, 0, 0, 0 }
@ -118,22 +92,22 @@ int main( int argc, char **argv )
switch (c) { switch (c) {
case 'h': case 'h':
printf("%s", qPrintable(app.translate("main","%1\n" printf("%s\n"
"Usage: %2 [--device=\"/device/path\"] [--notray|--force-tray] [\"layout name\"]\n" "Usage: %s [--device=\"/device/path\"] [--tray|--notray] [\"layout name\"]\n"
"\n" "\n"
"Options:\n" "Options:\n"
" -h, --help Print this help message.\n" " -h, --help Print this help message.\n"
" -d, --device=PATH Look for joystick devices in PATH. This should\n" " -d, --device=PATH Look for joystick devices in PATH. This should\n"
" be something like \"/dev/input\" if your game\n" " be something like \"/dev/input\" if your game\n"
" devices are in /dev/input/js0, /dev/input/js1, etc.\n" " devices are in /dev/input/js0, /dev/input/js1, etc.\n"
" -t, --force-tray Force to use a system tray icon.\n" " -t, --tray Use a system tray icon instead of floating window.\n"
" -T, --notray Do not use a system tray icon. This is useful for\n" " -T, --notray Do not use a system tray icon (default).\n"
" window managers that don't support this feature.\n" " -u, --update Force a running instance of ThunderPad to update its\n"
" -u, --update Force a running instance of QJoyPad to update its\n"
" list of devices and layouts.\n" " list of devices and layouts.\n"
" \"layout name\" Load the given layout in an already running\n" " \"layout name\" Load the given layout in an already running\n"
" instance of QJoyPad, or start QJoyPad using the\n" " instance of ThunderPad, or start ThunderPad using the\n"
" given layout.\n").arg(QJOYPAD_NAME, argc > 0 ? argv[0] : "qjoypad"))); " given layout.\n",
THUNDERPAD_NAME, argc > 0 ? argv[0] : "thunderpad");
return 0; return 0;
case 'd': case 'd':
@ -141,8 +115,8 @@ int main( int argc, char **argv )
devdir = optarg; devdir = optarg;
} }
else { else {
errorBox(app.translate("main","Not a directory"), errorBox("Not a directory",
app.translate("main","Path is not a directory: %1").arg(optarg)); QString("Path is not a directory: %1").arg(optarg));
return 1; return 1;
} }
break; break;
@ -161,9 +135,8 @@ int main( int argc, char **argv )
break; break;
case '?': case '?':
fprintf(stderr, "%s", qPrintable(app.translate("main", fprintf(stderr, "Illegal argument.\n"
"Illeagal argument.\n" "See `%s --help` for more information\n", argc > 0 ? argv[0] : "thunderpad");
"See `%1 --help` for more information\n").arg(argc > 0 ? argv[0] : "qjoypad")));
return 1; return 1;
} }
} }
@ -172,9 +145,8 @@ int main( int argc, char **argv )
layout = argv[optind ++]; layout = argv[optind ++];
if (optind < argc) { if (optind < argc) {
fprintf(stderr, "%s", qPrintable(app.translate("main", fprintf(stderr, "Too many arguments.\n"
"Too many arguments.\n" "See `%s --help` for more information\n", argc > 0 ? argv[0] : "thunderpad");
"See `%1 --help` for more information\n").arg(argc > 0 ? argv[0] : "qjoypad")));
return 1; return 1;
} }
} }
@ -197,8 +169,8 @@ int main( int argc, char **argv )
//create a pid lock file. //create a pid lock file.
QFile pidFile( "/tmp/qjoypad.pid" ); QFile pidFile( "/tmp/thunderpad.pid" );
//if that file already exists, then qjoypad is already running! //if that file already exists, then thunderpad is already running!
if (pidFile.exists()) if (pidFile.exists())
{ {
int pid = 0; int pid = 0;
@ -214,8 +186,8 @@ int main( int argc, char **argv )
//however, if we are setting the layout or updating the device //however, if we are setting the layout or updating the device
//list, this is not an error and we shouldn't make one! //list, this is not an error and we shouldn't make one!
if (layout.isEmpty() && !update) if (layout.isEmpty() && !update)
errorBox(app.translate("main","Instance Error"), errorBox("Instance Error",
app.translate("main","There is already a running instance of QJoyPad; please close\nthe old instance before starting a new one.")); "There is already a running instance of ThunderPad; please close\nthe old instance before starting a new one.");
else { else {
//if one of these is the case, send the appropriate signal! //if one of these is the case, send the appropriate signal!
if (update) { if (update) {
@ -243,8 +215,8 @@ int main( int argc, char **argv )
sleep(1); sleep(1);
sleepCounter++; sleepCounter++;
if (sleepCounter > 20) { if (sleepCounter > 20) {
errorBox(app.translate("main","System tray isn't loading"), errorBox("System tray isn't loading",
app.translate("main","Waited more than 20 seconds for the system tray to load. Giving up.")); "Waited more than 20 seconds for the system tray to load. Giving up.");
return 1; return 1;
} }
} }

View File

@ -1,5 +1,5 @@
#ifndef QJOYPAD_QUICKSET_H #ifndef THUNDERPAD_QUICKSET_H
#define QJOYPAD_QUICKSET_H #define THUNDERPAD_QUICKSET_H
//for building the dialog //for building the dialog
#include <QLayout> #include <QLayout>

9
thunderpad.desktop Executable file
View File

@ -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.

View File

@ -1,667 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS>
<TS version="2.0" language="de_DE">
<context>
<name>Axis</name>
<message>
<location filename="../src/axis.cpp" line="270"/>
<source>Axis %1</source>
<translation type="unfinished">Achse %1</translation>
</message>
<message>
<location filename="../src/axis.cpp" line="289"/>
<source>KEYBOARD/MOUSE</source>
<translation type="unfinished">TASTATUR/MAUS</translation>
</message>
<message>
<location filename="../src/axis.cpp" line="292"/>
<location filename="../src/axis.cpp" line="303"/>
<source>MOUSE</source>
<translation type="unfinished">MAUS</translation>
</message>
<message>
<location filename="../src/axis.cpp" line="295"/>
<source>KEYBOARD</source>
<translation type="unfinished">TASTATUR</translation>
</message>
<message>
<location filename="../src/axis.cpp" line="299"/>
<source>THROTTLE</source>
<translation type="unfinished">Drossel</translation>
</message>
</context>
<context>
<name>AxisEdit</name>
<message>
<location filename="../src/axis_edit.cpp" line="26"/>
<source>&amp;Gradient</source>
<translation type="unfinished">&amp;Verlauf</translation>
</message>
<message>
<location filename="../src/axis_edit.cpp" line="32"/>
<source>Keyboard/Mouse Button</source>
<translation type="unfinished">Tastatur-/Maus-Taste</translation>
</message>
<message>
<location filename="../src/axis_edit.cpp" line="33"/>
<source>Mouse (Vert.)</source>
<translation type="unfinished">Maus (Vert.)</translation>
</message>
<message>
<location filename="../src/axis_edit.cpp" line="34"/>
<source>Mouse (Vert. Rev.)</source>
<translation type="unfinished">Maus (Vert. Inv.)</translation>
</message>
<message>
<location filename="../src/axis_edit.cpp" line="35"/>
<source>Mouse (Hor.)</source>
<translation type="unfinished">Maus (Hor.)</translation>
</message>
<message>
<location filename="../src/axis_edit.cpp" line="36"/>
<source>Mouse (Hor. Rev.)</source>
<translation type="unfinished">Maus (Hor. Inv.)</translation>
</message>
<message>
<location filename="../src/axis_edit.cpp" line="41"/>
<source>Linear</source>
<translation type="unfinished">Linear</translation>
</message>
<message>
<location filename="../src/axis_edit.cpp" line="42"/>
<source>Quadratic</source>
<translation type="unfinished">Quadratisch</translation>
</message>
<message>
<location filename="../src/axis_edit.cpp" line="43"/>
<source>Cubic</source>
<translation type="unfinished">Cubisch</translation>
</message>
<message>
<location filename="../src/axis_edit.cpp" line="44"/>
<source>Quadratic Extreme</source>
<translation type="unfinished">Quadratisches Extrem</translation>
</message>
<message>
<location filename="../src/axis_edit.cpp" line="45"/>
<source>Power Function</source>
<translation type="unfinished">Potenzfunktion</translation>
</message>
<message>
<location filename="../src/axis_edit.cpp" line="58"/>
<source>&amp;Mouse Speed</source>
<translation type="unfinished">&amp;Mausgeschwindigkeit</translation>
</message>
<message>
<location filename="../src/axis_edit.cpp" line="65"/>
<source>&amp;Sensitivity</source>
<translation type="unfinished">&amp;Sensibilität</translation>
</message>
<message>
<location filename="../src/axis_edit.cpp" line="89"/>
<source>Neg. Throttle</source>
<translation type="unfinished">Neg. Drossel</translation>
</message>
<message>
<location filename="../src/axis_edit.cpp" line="90"/>
<source>No Throttle</source>
<translation type="unfinished">Keine Drossel</translation>
</message>
<message>
<location filename="../src/axis_edit.cpp" line="91"/>
<source>Pos. Throttle</source>
<translation type="unfinished">Pos. Drossel</translation>
</message>
</context>
<context>
<name>Button</name>
<message>
<location filename="../src/button.cpp" line="127"/>
<source>Button %1</source>
<translation type="unfinished">Taste %1</translation>
</message>
<message>
<location filename="../src/button.cpp" line="132"/>
<source>%1 : Mouse %2</source>
<translation type="unfinished">%1: Maus %2</translation>
</message>
<message>
<location filename="../src/button.cpp" line="135"/>
<source>%1 : %2</source>
<translation type="unfinished">%1: %2</translation>
</message>
</context>
<context>
<name>ButtonEdit</name>
<message>
<location filename="../src/button_edit.cpp" line="12"/>
<source>Set %1</source>
<translation type="unfinished">Setze %1</translation>
</message>
<message>
<location filename="../src/button_edit.cpp" line="23"/>
<source>&amp;Sticky</source>
<translation type="unfinished">&amp;Klebrig</translation>
</message>
<message>
<location filename="../src/button_edit.cpp" line="26"/>
<source>&amp;Rapid Fire</source>
<translation type="unfinished">&amp;Schnellfeuer</translation>
</message>
</context>
<context>
<name>FloatingIcon</name>
<message>
<location filename="../src/icon.cpp" line="12"/>
<source>%1 Floating Icon</source>
<translation type="unfinished">%1 Schwebendes Symbol</translation>
</message>
</context>
<context>
<name>GetKey</name>
<message>
<location filename="../src/getkey.cpp" line="21"/>
<source>Choose a key</source>
<translation type="unfinished">Wähle eine Taste</translation>
</message>
<message>
<location filename="../src/getkey.cpp" line="27"/>
<source>Choose a new key or mouse button for %1</source>
<translation type="unfinished">Whähle eine neue Taste oder einen neuen Mausknopf für %1</translation>
</message>
<message>
<location filename="../src/getkey.cpp" line="27"/>
<source>Choose a new key for %1</source>
<translation type="unfinished">Wähle eine neue Taste für %1</translation>
</message>
<message>
<location filename="../src/getkey.cpp" line="33"/>
<source>
(Ctrl-X for no key)</source>
<translation type="unfinished">
(Ctrl-X für keine Taste)</translation>
</message>
</context>
<context>
<name>JoyPad</name>
<message>
<location filename="../src/joypad.cpp" line="109"/>
<source>Joystick %1 (%2)</source>
<translation type="unfinished">Joystick %1 (%2)</translation>
</message>
<message>
<location filename="../src/joypad.cpp" line="152"/>
<location filename="../src/joypad.cpp" line="159"/>
<location filename="../src/joypad.cpp" line="172"/>
<location filename="../src/joypad.cpp" line="179"/>
<location filename="../src/joypad.cpp" line="185"/>
<source>Layout file error</source>
<translation type="unfinished">Belegungsdatei-Fehler</translation>
</message>
<message>
<location filename="../src/joypad.cpp" line="152"/>
<location filename="../src/joypad.cpp" line="172"/>
<source>Expected &apos;:&apos;, found &apos;%1&apos;.</source>
<translation type="unfinished">&apos;;&apos; erwartet, &apos;%1&apos; vorgefunden.</translation>
</message>
<message>
<location filename="../src/joypad.cpp" line="159"/>
<source>Error reading Button %1</source>
<translation type="unfinished">Fehler beim Lesen der Taste %1</translation>
</message>
<message>
<location filename="../src/joypad.cpp" line="179"/>
<source>Error reading Axis %1</source>
<translation type="unfinished">Fehler beim Lesen der Achse %1</translation>
</message>
<message>
<location filename="../src/joypad.cpp" line="185"/>
<source>Error while reading layout. Unrecognized word: %1</source>
<translation type="unfinished">Fehler beim Lesen der Belegung. Unbekanntes Wort: %1</translation>
</message>
</context>
<context>
<name>JoyPadWidget</name>
<message>
<location filename="../src/joypadw.cpp" line="38"/>
<source>Clear</source>
<translation type="unfinished">Löschen</translation>
</message>
<message>
<location filename="../src/joypadw.cpp" line="42"/>
<source>Quick Set</source>
<translation type="unfinished">Schnell Setzen</translation>
</message>
</context>
<context>
<name>KeyButton</name>
<message>
<location filename="../src/keycode.cpp" line="83"/>
<location filename="../src/keycode.cpp" line="103"/>
<source>Mouse %1</source>
<translation type="unfinished">Maus %1</translation>
</message>
</context>
<context>
<name>LayoutEdit</name>
<message>
<location filename="../src/layout_edit.cpp" line="40"/>
<source>Add Layout</source>
<translation type="unfinished">Belegung Hinzufügen</translation>
</message>
<message>
<location filename="../src/layout_edit.cpp" line="52"/>
<source>Remove Layout</source>
<translation type="unfinished">Belegung Entfernen</translation>
</message>
<message>
<location filename="../src/layout_edit.cpp" line="56"/>
<source>&amp;Rename</source>
<translation type="unfinished">&amp;Umbenennen</translation>
</message>
<message>
<location filename="../src/layout_edit.cpp" line="57"/>
<source>Rename Layout</source>
<translation type="unfinished">Belegung Umbenennen</translation>
</message>
<message>
<location filename="../src/layout_edit.cpp" line="67"/>
<source>&amp;Import</source>
<translation type="unfinished">&amp;Importieren</translation>
</message>
<message>
<location filename="../src/layout_edit.cpp" line="71"/>
<source>E&amp;xport</source>
<translation type="unfinished">E&amp;xportieren</translation>
</message>
<message>
<location filename="../src/layout_edit.cpp" line="75"/>
<source>&amp;Save</source>
<translation type="unfinished">&amp;Speichern</translation>
</message>
<message>
<location filename="../src/layout_edit.cpp" line="79"/>
<source>Re&amp;vert</source>
<translation type="unfinished">&amp;Zurücksetzen</translation>
</message>
<message>
<location filename="../src/layout_edit.cpp" line="121"/>
<source>&amp;Close Dialog</source>
<translation type="unfinished">&amp;Fenster Schließen</translation>
</message>
<message>
<location filename="../src/layout_edit.cpp" line="124"/>
<source>&amp;Quit</source>
<translation type="unfinished">&amp;Beenden</translation>
</message>
<message>
<location filename="../src/layout_edit.cpp" line="155"/>
<source>[NO LAYOUT]</source>
<translation type="unfinished">[KEINE BELEGUNG]</translation>
</message>
</context>
<context>
<name>LayoutManager</name>
<message>
<location filename="../src/layout.cpp" line="17"/>
<source>Update &amp;Joystick Devices</source>
<translation type="unfinished">&amp;Joysticks Aktualisieren</translation>
</message>
<message>
<location filename="../src/layout.cpp" line="18"/>
<source>Update &amp;Layout List</source>
<translation type="unfinished">Be&amp;legungsliste Aktualisieren</translation>
</message>
<message>
<location filename="../src/layout.cpp" line="19"/>
<source>&amp;Quit</source>
<translation type="unfinished">&amp;Beenden</translation>
</message>
<message>
<location filename="../src/layout.cpp" line="28"/>
<source>UDev Error</source>
<translation type="unfinished">UDev Fehler</translation>
</message>
<message>
<location filename="../src/layout.cpp" line="28"/>
<source>Error creating UDev monitor. QJoyPad will still work, but it won&apos;t automatically update the joypad device list.</source>
<translation type="unfinished">Fehler beim Erzeugen des UDev Monitors. QJoypad wird dennoch funktionieren, aber es wird nicht automatisch die Joypad-Liste aktualisieren.</translation>
</message>
<message>
<location filename="../src/layout.cpp" line="174"/>
<location filename="../src/layout.cpp" line="180"/>
<location filename="../src/layout.cpp" line="211"/>
<location filename="../src/layout.cpp" line="221"/>
<location filename="../src/layout.cpp" line="235"/>
<location filename="../src/layout.cpp" line="250"/>
<source>Load error</source>
<translation type="unfinished">Lade-Fehler</translation>
</message>
<message>
<location filename="../src/layout.cpp" line="174"/>
<source>Failed to find a layout named %1.</source>
<translation type="unfinished">Belegung mit Namen %1 wurde nicht gefunden.</translation>
</message>
<message>
<location filename="../src/layout.cpp" line="180"/>
<source>Error reading from file: %1</source>
<translation type="unfinished">Fehler beim lesen der Datei: %1</translation>
</message>
<message>
<location filename="../src/layout.cpp" line="212"/>
<source>Error reading joystick definition. Unexpected token &quot;%1&quot;. Expected a positive number.</source>
<translation type="unfinished">Fehler beim Lesen der Joystick-Definition. Unerwartets Token &quot;%1&quot;. Eine positive Zahl wurde erwartet.</translation>
</message>
<message>
<location filename="../src/layout.cpp" line="222"/>
<source>Error reading joystick definition. Unexpected character &quot;%1&quot;. Expected &apos;{&apos;.</source>
<translation type="unfinished">Fehler beim Lesen der Joystick-Definition. Unerwartets Zeichen &quot;%1&quot;. &apos;{&apos; wurde erwartet.</translation>
</message>
<message>
<location filename="../src/layout.cpp" line="235"/>
<source>Error reading definition for joystick %1.</source>
<translation type="unfinished">Fehler beim Lesen der Definition von Joystick %1.</translation>
</message>
<message>
<location filename="../src/layout.cpp" line="251"/>
<source>Error reading joystick definition. Unexpected token &quot;%1&quot;. Expected &quot;Joystick&quot;.</source>
<translation type="unfinished">Fehler beim Lesen der Joystick-Definition. Unerwartetes Token &quot;%1&quot;. &quot;Joystick&quot; wurde erwertet.</translation>
</message>
<message>
<location filename="../src/layout.cpp" line="323"/>
<location filename="../src/layout.cpp" line="338"/>
<location filename="../src/layout.cpp" line="342"/>
<location filename="../src/layout.cpp" line="348"/>
<source>Save error</source>
<translation type="unfinished">Fehler beim Speichern</translation>
</message>
<message>
<location filename="../src/layout.cpp" line="323"/>
<source>Could not open file %1, layout not saved.</source>
<translation type="unfinished">Konnte Datei %1 nicht öffnen, Belegung wurde nicht gespeichert.</translation>
</message>
<message>
<location filename="../src/layout.cpp" line="331"/>
<source>Name new layout - %1</source>
<translation type="unfinished">Neue Belegung benennen - %1</translation>
</message>
<message>
<location filename="../src/layout.cpp" line="367"/>
<source>Import layout - %1</source>
<translation type="unfinished">Belegung Importieren - %1</translation>
</message>
<message>
<location filename="../src/layout.cpp" line="371"/>
<location filename="../src/layout.cpp" line="417"/>
<source>QJoyPad layout files (*.lyt)</source>
<translation type="unfinished">QJoyPad Belegung-Dateien (*.lyt)</translation>
</message>
<message>
<location filename="../src/layout.cpp" line="372"/>
<location filename="../src/layout.cpp" line="418"/>
<source>Any files (*)</source>
<translation type="unfinished">Alle Dateien (*)</translation>
</message>
<message>
<location filename="../src/layout.cpp" line="387"/>
<source>Import error</source>
<translation type="unfinished">Fehler beim Importieren</translation>
</message>
<message>
<location filename="../src/layout.cpp" line="387"/>
<source>Cannot import file from QJoyPad settings directory.</source>
<translation type="unfinished">Kann Datei aus dem QJoyPad Einstellungsverzeichnis nicht importieren.</translation>
</message>
<message>
<location filename="../src/layout.cpp" line="393"/>
<source>Layout exists</source>
<translation type="unfinished">Belegung existiert</translation>
</message>
<message>
<location filename="../src/layout.cpp" line="394"/>
<source>Layout %1 exists. Do you want to overwrite it?</source>
<translation type="unfinished">Belegung %1 existiert. Wollen Sie sie überschreiben?</translation>
</message>
<message>
<location filename="../src/layout.cpp" line="395"/>
<source>Over&amp;write</source>
<translation type="unfinished">Über&amp;schreiben</translation>
</message>
<message>
<location filename="../src/layout.cpp" line="395"/>
<location filename="../src/layout.cpp" line="437"/>
<source>&amp;Cancel</source>
<translation type="unfinished">&amp;Abbrechen</translation>
</message>
<message>
<location filename="../src/layout.cpp" line="413"/>
<source>Export layout - %1</source>
<translation type="unfinished">Belegung Exportieren - %1</translation>
</message>
<message>
<location filename="../src/layout.cpp" line="436"/>
<source>Delete layout? - %1</source>
<translation type="unfinished">Belegung löschen? - %1</translation>
</message>
<message>
<location filename="../src/layout.cpp" line="437"/>
<source>&amp;Delete</source>
<translation type="unfinished">&amp;Löschen</translation>
</message>
<message>
<location filename="../src/layout.cpp" line="332"/>
<source>Enter a name for the new layout:</source>
<translation type="unfinished">Name der neuen Belegung eingeben:</translation>
</message>
<message>
<location filename="../src/layout.cpp" line="338"/>
<location filename="../src/layout.cpp" line="463"/>
<source>Layout name cannot be empty.</source>
<translation type="unfinished">Belegungsname kann nicht leer sein.</translation>
</message>
<message>
<location filename="../src/layout.cpp" line="342"/>
<location filename="../src/layout.cpp" line="467"/>
<source>Layout name may not contain a &apos;/&apos; (slash).</source>
<translation type="unfinished">Belegungsname kann keinen &apos;/&apos; (Schrägstrich) enthalten.</translation>
</message>
<message>
<location filename="../src/layout.cpp" line="348"/>
<source>That name&apos;s already taken!</source>
<translation type="unfinished">Dieser Name ist bereits belegt!</translation>
</message>
<message>
<location filename="../src/layout.cpp" line="437"/>
<source>Remove layout %1 permanently from your hard drive?</source>
<translation type="unfinished">Belegung %1 permanent von ihrer Festplatte löschen?</translation>
</message>
<message>
<location filename="../src/layout.cpp" line="442"/>
<source>Remove error</source>
<translation type="unfinished">Fehler beim Entfernen</translation>
</message>
<message>
<location filename="../src/layout.cpp" line="442"/>
<source>Could not remove file %1</source>
<translation type="unfinished">Konnte Datei %1 nicht entfernen</translation>
</message>
<message>
<location filename="../src/layout.cpp" line="456"/>
<source>Rename layout - %1</source>
<translation type="unfinished">Belegung umbenennen - %1</translation>
</message>
<message>
<location filename="../src/layout.cpp" line="457"/>
<source>Enter a new name for the layout:</source>
<translation type="unfinished">Geben Sie einen neuen Belegungsnamen ein:</translation>
</message>
<message>
<location filename="../src/layout.cpp" line="463"/>
<location filename="../src/layout.cpp" line="467"/>
<location filename="../src/layout.cpp" line="474"/>
<location filename="../src/layout.cpp" line="479"/>
<source>Rename error</source>
<translation type="unfinished">Umbenennungsfehler</translation>
</message>
<message>
<location filename="../src/layout.cpp" line="474"/>
<source>Layout with name %1 already exists.</source>
<translation type="unfinished">Belegung mit dem Namen %1 existiert bereits.</translation>
</message>
<message>
<location filename="../src/layout.cpp" line="479"/>
<source>Error renaming layout.</source>
<translation type="unfinished">Fehler beim Umbenennen einer Belegung.</translation>
</message>
<message>
<location filename="../src/layout.cpp" line="522"/>
<source>No joystick devices available</source>
<translation type="unfinished">Keine Joysticks verfügbar</translation>
</message>
<message>
<location filename="../src/layout.cpp" line="523"/>
<source>No joystick devices are currently available to configure.
Please plug in a gaming device and select
&quot;Update Joystick Devices&quot; from the popup menu.</source>
<translation type="unfinished">Zur Zeit sind keine Joysticks zur Konfiguration verfügbar.
Bitte schließen Sie ein entsprechendes Gerät an und
wählen Sie &quot;Joysticks Aktualisieren&quot; im Popup-Menü.</translation>
</message>
<message>
<location filename="../src/layout.cpp" line="583"/>
<source>[NO LAYOUT]</source>
<translation type="unfinished">[KEINE BELEGUNG]</translation>
</message>
</context>
<context>
<name>QuickSet</name>
<message>
<location filename="../src/quickset.cpp" line="7"/>
<source>Set %1</source>
<translation type="unfinished">Setze %1</translation>
</message>
<message>
<location filename="../src/quickset.cpp" line="13"/>
<source>Press any button or axis and
you will be prompted for a key.</source>
<translation type="unfinished">Drücken sie eine belibige Taste oder Achse und
Sie werden nach einer Taste gefragt werden.</translation>
</message>
<message>
<location filename="../src/quickset.cpp" line="15"/>
<source>Done</source>
<translation type="unfinished">Fertig</translation>
</message>
<message>
<location filename="../src/quickset.cpp" line="52"/>
<source>%1, positive</source>
<translation type="unfinished">%1, positiv</translation>
</message>
<message>
<location filename="../src/quickset.cpp" line="52"/>
<source>%1, negative</source>
<translation type="unfinished">%1, negativ</translation>
</message>
</context>
<context>
<name>main</name>
<message>
<location filename="../src/main.cpp" line="74"/>
<source>Couldn&apos;t create the QJoyPad save directory</source>
<translation type="unfinished">Konnte das QJoyPad Seicher-Verzeichnis nicht anlegen</translation>
</message>
<message>
<location filename="../src/main.cpp" line="75"/>
<source>Couldn&apos;t create the QJoyPad save directory: %s</source>
<translation type="unfinished">Konnte das QJoyPad Seicher-Verzeichnis nicht anlegen: %s</translation>
</message>
<message>
<location filename="../src/main.cpp" line="106"/>
<source>%1
Usage: %2 [--device=&quot;/device/path&quot;] [--notray|--force-tray] [&quot;layout name&quot;]
Options:
-h, --help Print this help message.
-d, --device=PATH Look for joystick devices in PATH. This should
be something like &quot;/dev/input&quot; 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&apos;t support this feature.
-u, --update Force a running instance of QJoyPad to update its
list of devices and layouts.
&quot;layout name&quot; Load the given layout in an already running
instance of QJoyPad, or start QJoyPad using the
given layout.
</source>
<translation type="unfinished">%1
Verwendung: %2 [--device=&quot;/Geräte/Pfad&quot;] [--notray|--force-tray] [&quot;Belegungsname&quot;]
Optionen:
-h, --help Gibt diesen Hilfetext aus.
-d, --device=PFAD In PFAD nach Joystick-Geräten suchen. Dies sollte
&quot;/dev/input&quot; 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.
&quot;Belegungsname&quot; Lade die angegebenen Belegung in einer bereits laufenden
Instanz von QJoyPad oder starte QJoyPad mit der gegebenen
Belegung.
</translation>
</message>
<message>
<location filename="../src/main.cpp" line="129"/>
<source>Not a directory</source>
<translation type="unfinished">Kein Verzeichnis</translation>
</message>
<message>
<location filename="../src/main.cpp" line="130"/>
<source>Path is not a directory: %1</source>
<translation type="unfinished">Pfad ist kein Verzeichnis: %1</translation>
</message>
<message>
<location filename="../src/main.cpp" line="149"/>
<source>Illeagal argument.
See `%1 --help` for more information
</source>
<translation type="unfinished">Ungülltiges Argument.
Siehe `%1 --help` für mehr Information
</translation>
</message>
<message>
<location filename="../src/main.cpp" line="160"/>
<source>Too many arguments.
See `%1 --help` for more information
</source>
<translation type="unfinished">Zu viele Argumente.
Siehe `%1 --help` für mehr Information
</translation>
</message>
<message>
<location filename="../src/main.cpp" line="202"/>
<source>Instance Error</source>
<translation type="unfinished">Instanzierungs-Fehler</translation>
</message>
<message>
<location filename="../src/main.cpp" line="203"/>
<source>There is already a running instance of QJoyPad; please close
the old instance before starting a new one.</source>
<translation type="unfinished">Es läuft bereits eine Instanz von QJoyPad; bitte schließen
sie die alte Instanz bevor sie eine neue öffnen.</translation>
</message>
<message>
<location filename="../src/main.cpp" line="231"/>
<source>System tray isn&apos;t loading</source>
<translation type="unfinished">Systemablage startet nicht</translation>
</message>
<message>
<location filename="../src/main.cpp" line="232"/>
<source>Waited more than 20 seconds for the system tray to load. Giving up.</source>
<translation type="unfinished">Es wurde mehr als 20 Sekunden auf die Systemablage gewartet. Gebe auf.</translation>
</message>
</context>
</TS>

View File

@ -1,666 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS>
<TS version="2.1" language="nl">
<context>
<name>Axis</name>
<message>
<location filename="../src/axis.cpp" line="270"/>
<source>Axis %1</source>
<translation>As %1</translation>
</message>
<message>
<location filename="../src/axis.cpp" line="289"/>
<source>KEYBOARD/MOUSE</source>
<translation>TOETSENBORD/MUIS</translation>
</message>
<message>
<location filename="../src/axis.cpp" line="292"/>
<location filename="../src/axis.cpp" line="303"/>
<source>MOUSE</source>
<translation>MUIS</translation>
</message>
<message>
<location filename="../src/axis.cpp" line="295"/>
<source>KEYBOARD</source>
<translation>TOETSENBORD</translation>
</message>
<message>
<location filename="../src/axis.cpp" line="299"/>
<source>THROTTLE</source>
<translation>BEPERKEN</translation>
</message>
</context>
<context>
<name>AxisEdit</name>
<message>
<location filename="../src/axis_edit.cpp" line="26"/>
<source>&amp;Gradient</source>
<translation>&amp;Verloop</translation>
</message>
<message>
<location filename="../src/axis_edit.cpp" line="32"/>
<source>Keyboard/Mouse Button</source>
<translation>Toetsenbord-/muisknop</translation>
</message>
<message>
<location filename="../src/axis_edit.cpp" line="33"/>
<source>Mouse (Vert.)</source>
<translation>Muis (vert.)</translation>
</message>
<message>
<location filename="../src/axis_edit.cpp" line="34"/>
<source>Mouse (Vert. Rev.)</source>
<translation>Muis (vert. omgekeerd)</translation>
</message>
<message>
<location filename="../src/axis_edit.cpp" line="35"/>
<source>Mouse (Hor.)</source>
<translation>Muis (hor.)</translation>
</message>
<message>
<location filename="../src/axis_edit.cpp" line="36"/>
<source>Mouse (Hor. Rev.)</source>
<translation>Muis (hor. omgekeerd)</translation>
</message>
<message>
<location filename="../src/axis_edit.cpp" line="41"/>
<source>Linear</source>
<translation>Linear</translation>
</message>
<message>
<location filename="../src/axis_edit.cpp" line="42"/>
<source>Quadratic</source>
<translation>Quadratisch</translation>
</message>
<message>
<location filename="../src/axis_edit.cpp" line="43"/>
<source>Cubic</source>
<translation>Cubisch</translation>
</message>
<message>
<location filename="../src/axis_edit.cpp" line="44"/>
<source>Quadratic Extreme</source>
<translation>Quadratisch (extreem)</translation>
</message>
<message>
<location filename="../src/axis_edit.cpp" line="45"/>
<source>Power Function</source>
<translation>Energiefunctie</translation>
</message>
<message>
<location filename="../src/axis_edit.cpp" line="58"/>
<source>&amp;Mouse Speed</source>
<translation>&amp;Muissnelheid</translation>
</message>
<message>
<location filename="../src/axis_edit.cpp" line="65"/>
<source>&amp;Sensitivity</source>
<translation>&amp;Gevoeligheid</translation>
</message>
<message>
<location filename="../src/axis_edit.cpp" line="89"/>
<source>Neg. Throttle</source>
<translation>Neg. beperking</translation>
</message>
<message>
<location filename="../src/axis_edit.cpp" line="90"/>
<source>No Throttle</source>
<translation>Geen beperking</translation>
</message>
<message>
<location filename="../src/axis_edit.cpp" line="91"/>
<source>Pos. Throttle</source>
<translation>Pos. beperking</translation>
</message>
</context>
<context>
<name>Button</name>
<message>
<location filename="../src/button.cpp" line="127"/>
<source>Button %1</source>
<translation>Knop %1</translation>
</message>
<message>
<location filename="../src/button.cpp" line="132"/>
<source>%1 : Mouse %2</source>
<translation>%1: Muis %2</translation>
</message>
<message>
<location filename="../src/button.cpp" line="135"/>
<source>%1 : %2</source>
<translation>%1: %2</translation>
</message>
</context>
<context>
<name>ButtonEdit</name>
<message>
<location filename="../src/button_edit.cpp" line="12"/>
<source>Set %1</source>
<translation>%1 instellen</translation>
</message>
<message>
<location filename="../src/button_edit.cpp" line="23"/>
<source>&amp;Sticky</source>
<translation>Plaktoet&amp;s</translation>
</message>
<message>
<location filename="../src/button_edit.cpp" line="26"/>
<source>&amp;Rapid Fire</source>
<translation>&amp;Snelvuren</translation>
</message>
</context>
<context>
<name>FloatingIcon</name>
<message>
<location filename="../src/icon.cpp" line="12"/>
<source>%1 Floating Icon</source>
<translation>%1 zwevend pictogram</translation>
</message>
</context>
<context>
<name>GetKey</name>
<message>
<location filename="../src/getkey.cpp" line="21"/>
<source>Choose a key</source>
<translation>Kies een toets</translation>
</message>
<message>
<location filename="../src/getkey.cpp" line="27"/>
<source>Choose a new key or mouse button for %1</source>
<translation>Kies een toets of muisknop voor %1</translation>
</message>
<message>
<location filename="../src/getkey.cpp" line="27"/>
<source>Choose a new key for %1</source>
<translation>Kies een toets voor %1</translation>
</message>
<message>
<location filename="../src/getkey.cpp" line="33"/>
<source>
(Ctrl-X for no key)</source>
<translation>
(Ctrl-X om geen toets te gebruiken)</translation>
</message>
</context>
<context>
<name>JoyPad</name>
<message>
<location filename="../src/joypad.cpp" line="109"/>
<source>Joystick %1 (%2)</source>
<translation>Joystick %1 (%2)</translation>
</message>
<message>
<location filename="../src/joypad.cpp" line="152"/>
<location filename="../src/joypad.cpp" line="159"/>
<location filename="../src/joypad.cpp" line="172"/>
<location filename="../src/joypad.cpp" line="179"/>
<location filename="../src/joypad.cpp" line="185"/>
<source>Layout file error</source>
<translation>Fout in indelingsbestand</translation>
</message>
<message>
<location filename="../src/joypad.cpp" line="152"/>
<location filename="../src/joypad.cpp" line="172"/>
<source>Expected &apos;:&apos;, found &apos;%1&apos;.</source>
<translation>&apos;;&apos; verwacht; &apos;%1&apos; aangetroffen.</translation>
</message>
<message>
<location filename="../src/joypad.cpp" line="159"/>
<source>Error reading Button %1</source>
<translation>Fout tijdens uitlezen van knop %1</translation>
</message>
<message>
<location filename="../src/joypad.cpp" line="179"/>
<source>Error reading Axis %1</source>
<translation>Fout tijdens uitlezen van as %1</translation>
</message>
<message>
<location filename="../src/joypad.cpp" line="185"/>
<source>Error while reading layout. Unrecognized word: %1</source>
<translation>Fout tijdens uitlezen van indeling. Onbekend woord: %1</translation>
</message>
</context>
<context>
<name>JoyPadWidget</name>
<message>
<location filename="../src/joypadw.cpp" line="38"/>
<source>Clear</source>
<translation>Wissen</translation>
</message>
<message>
<location filename="../src/joypadw.cpp" line="42"/>
<source>Quick Set</source>
<translation>Snel instellen</translation>
</message>
</context>
<context>
<name>KeyButton</name>
<message>
<location filename="../src/keycode.cpp" line="83"/>
<location filename="../src/keycode.cpp" line="103"/>
<source>Mouse %1</source>
<translation>Muis %1</translation>
</message>
</context>
<context>
<name>LayoutEdit</name>
<message>
<location filename="../src/layout_edit.cpp" line="40"/>
<source>Add Layout</source>
<translation>Indeling toevoegen</translation>
</message>
<message>
<location filename="../src/layout_edit.cpp" line="52"/>
<source>Remove Layout</source>
<translation>Indeling verwijderen</translation>
</message>
<message>
<location filename="../src/layout_edit.cpp" line="56"/>
<source>&amp;Rename</source>
<translation>&amp;Naam wijzigen</translation>
</message>
<message>
<location filename="../src/layout_edit.cpp" line="57"/>
<source>Rename Layout</source>
<translation>Indelingsnaam wijzigen</translation>
</message>
<message>
<location filename="../src/layout_edit.cpp" line="67"/>
<source>&amp;Import</source>
<translation>&amp;Importeren</translation>
</message>
<message>
<location filename="../src/layout_edit.cpp" line="71"/>
<source>E&amp;xport</source>
<translation>E&amp;xporteren</translation>
</message>
<message>
<location filename="../src/layout_edit.cpp" line="75"/>
<source>&amp;Save</source>
<translation>Op&amp;slaan</translation>
</message>
<message>
<location filename="../src/layout_edit.cpp" line="79"/>
<source>Re&amp;vert</source>
<translation>&amp;Terugdraaien</translation>
</message>
<message>
<location filename="../src/layout_edit.cpp" line="121"/>
<source>&amp;Close Dialog</source>
<translation>&amp;Venster sluiten</translation>
</message>
<message>
<location filename="../src/layout_edit.cpp" line="124"/>
<source>&amp;Quit</source>
<translation>&amp;Afsluiten</translation>
</message>
<message>
<location filename="../src/layout_edit.cpp" line="155"/>
<source>[NO LAYOUT]</source>
<translation>[GEEN INDELING]</translation>
</message>
</context>
<context>
<name>LayoutManager</name>
<message>
<location filename="../src/layout.cpp" line="17"/>
<source>Update &amp;Joystick Devices</source>
<translation>Zoeken naar &amp;joysticks</translation>
</message>
<message>
<location filename="../src/layout.cpp" line="18"/>
<source>Update &amp;Layout List</source>
<translation>Inde&amp;lingslijst verversen</translation>
</message>
<message>
<location filename="../src/layout.cpp" line="19"/>
<source>&amp;Quit</source>
<translation>&amp;Afsluiten</translation>
</message>
<message>
<location filename="../src/layout.cpp" line="28"/>
<source>UDev Error</source>
<translation>UDev-fout</translation>
</message>
<message>
<location filename="../src/layout.cpp" line="28"/>
<source>Error creating UDev monitor. QJoyPad will still work, but it won&apos;t automatically update the joypad device list.</source>
<translation>Fout tijdens creëren van UDev-monitor. QJoypad werkt nog steeds, maar de joypadlijst wordt niet automatisch bijgewerkt.</translation>
</message>
<message>
<location filename="../src/layout.cpp" line="174"/>
<location filename="../src/layout.cpp" line="180"/>
<location filename="../src/layout.cpp" line="211"/>
<location filename="../src/layout.cpp" line="221"/>
<location filename="../src/layout.cpp" line="235"/>
<location filename="../src/layout.cpp" line="250"/>
<source>Load error</source>
<translation>Fout tijdens laden</translation>
</message>
<message>
<location filename="../src/layout.cpp" line="174"/>
<source>Failed to find a layout named %1.</source>
<translation>Geen indeling aangetroffen met de naam &apos;%1&apos;.</translation>
</message>
<message>
<location filename="../src/layout.cpp" line="180"/>
<source>Error reading from file: %1</source>
<translation>Fout tijdens uitlezen van bestand: %1</translation>
</message>
<message>
<location filename="../src/layout.cpp" line="212"/>
<source>Error reading joystick definition. Unexpected token &quot;%1&quot;. Expected a positive number.</source>
<translation>Fout tijdens uitlezen van joystick-definitie. Onverwachte sleutel &apos;%1&apos;. Er had een positief getal moeten staan.</translation>
</message>
<message>
<location filename="../src/layout.cpp" line="222"/>
<source>Error reading joystick definition. Unexpected character &quot;%1&quot;. Expected &apos;{&apos;.</source>
<translation>Fout tijdens uitlezen van joystick-definitie. Onverwacht teken &apos;%1&apos;. Er had &apos;{&apos; moeten staan.</translation>
</message>
<message>
<location filename="../src/layout.cpp" line="235"/>
<source>Error reading definition for joystick %1.</source>
<translation>Fout tijdens uitlezen van joystick-definitie &apos;%1&apos;.</translation>
</message>
<message>
<location filename="../src/layout.cpp" line="251"/>
<source>Error reading joystick definition. Unexpected token &quot;%1&quot;. Expected &quot;Joystick&quot;.</source>
<translation>Fout tijdens uitlezen van joystick-definitie. Onverwachte sleutel &apos;%1&apos;. Er had &apos;Joystick&apos; moeten staan.</translation>
</message>
<message>
<location filename="../src/layout.cpp" line="323"/>
<location filename="../src/layout.cpp" line="338"/>
<location filename="../src/layout.cpp" line="342"/>
<location filename="../src/layout.cpp" line="348"/>
<source>Save error</source>
<translation>Fout tijdens opslaan</translation>
</message>
<message>
<location filename="../src/layout.cpp" line="323"/>
<source>Could not open file %1, layout not saved.</source>
<translation>Kan &apos;%1&apos; niet openen; de indeling is niet opgeslagen.</translation>
</message>
<message>
<location filename="../src/layout.cpp" line="331"/>
<source>Name new layout - %1</source>
<translation>Geef de indeling een nieuwe naam - %1</translation>
</message>
<message>
<location filename="../src/layout.cpp" line="367"/>
<source>Import layout - %1</source>
<translation>Indeling importeren - %1</translation>
</message>
<message>
<location filename="../src/layout.cpp" line="371"/>
<location filename="../src/layout.cpp" line="417"/>
<source>QJoyPad layout files (*.lyt)</source>
<translation>QJoyPad-indelingsbestanden (*.lyt)</translation>
</message>
<message>
<location filename="../src/layout.cpp" line="372"/>
<location filename="../src/layout.cpp" line="418"/>
<source>Any files (*)</source>
<translation>Alle bestanden (*)</translation>
</message>
<message>
<location filename="../src/layout.cpp" line="387"/>
<source>Import error</source>
<translation>Fout tijdens importeren</translation>
</message>
<message>
<location filename="../src/layout.cpp" line="387"/>
<source>Cannot import file from QJoyPad settings directory.</source>
<translation>Kan het bestand uit de QJoyPad-instellingenmap niet importeren.</translation>
</message>
<message>
<location filename="../src/layout.cpp" line="393"/>
<source>Layout exists</source>
<translation>Indeling bestaat al</translation>
</message>
<message>
<location filename="../src/layout.cpp" line="394"/>
<source>Layout %1 exists. Do you want to overwrite it?</source>
<translation>De indeling &apos;%1&apos; bestaat al. Wil je deze overschrijven?</translation>
</message>
<message>
<location filename="../src/layout.cpp" line="395"/>
<source>Over&amp;write</source>
<translation>Over&amp;schrijven</translation>
</message>
<message>
<location filename="../src/layout.cpp" line="395"/>
<location filename="../src/layout.cpp" line="437"/>
<source>&amp;Cancel</source>
<translation>&amp;Annuleren</translation>
</message>
<message>
<location filename="../src/layout.cpp" line="413"/>
<source>Export layout - %1</source>
<translation>Indeling exporteren - %1</translation>
</message>
<message>
<location filename="../src/layout.cpp" line="436"/>
<source>Delete layout? - %1</source>
<translation>Wil je de indeling verwijderen? - %1</translation>
</message>
<message>
<location filename="../src/layout.cpp" line="437"/>
<source>&amp;Delete</source>
<translation>Verwij&amp;deren</translation>
</message>
<message>
<location filename="../src/layout.cpp" line="332"/>
<source>Enter a name for the new layout:</source>
<translation>Voer een naam in voor de nieuwe indeling:</translation>
</message>
<message>
<location filename="../src/layout.cpp" line="338"/>
<location filename="../src/layout.cpp" line="463"/>
<source>Layout name cannot be empty.</source>
<translation>De indeling moet een naam hebben.</translation>
</message>
<message>
<location filename="../src/layout.cpp" line="342"/>
<location filename="../src/layout.cpp" line="467"/>
<source>Layout name may not contain a &apos;/&apos; (slash).</source>
<translation>De naam mag geen &apos;/&apos; (schuine streep) bevatten.</translation>
</message>
<message>
<location filename="../src/layout.cpp" line="348"/>
<source>That name&apos;s already taken!</source>
<translation>Die naam is al in gebruik!</translation>
</message>
<message>
<location filename="../src/layout.cpp" line="437"/>
<source>Remove layout %1 permanently from your hard drive?</source>
<translation>Wil je de indeling &apos;%1&apos; permanent van je computer verwijderen?</translation>
</message>
<message>
<location filename="../src/layout.cpp" line="442"/>
<source>Remove error</source>
<translation>Fout tijdens verwijderen</translation>
</message>
<message>
<location filename="../src/layout.cpp" line="442"/>
<source>Could not remove file %1</source>
<translation>Kan &apos;%1&apos; niet verwijderen</translation>
</message>
<message>
<location filename="../src/layout.cpp" line="456"/>
<source>Rename layout - %1</source>
<translation>Indelingsnaam wijzigen - %1</translation>
</message>
<message>
<location filename="../src/layout.cpp" line="457"/>
<source>Enter a new name for the layout:</source>
<translation>Voer een naam in voor de indeling:</translation>
</message>
<message>
<location filename="../src/layout.cpp" line="463"/>
<location filename="../src/layout.cpp" line="467"/>
<location filename="../src/layout.cpp" line="474"/>
<location filename="../src/layout.cpp" line="479"/>
<source>Rename error</source>
<translation>Fout tijdens naamswijziging</translation>
</message>
<message>
<location filename="../src/layout.cpp" line="474"/>
<source>Layout with name %1 already exists.</source>
<translation>Er bestaat al een indeling genaamd &apos;%1&apos;.</translation>
</message>
<message>
<location filename="../src/layout.cpp" line="479"/>
<source>Error renaming layout.</source>
<translation>Fout tijdens naamswijziging.</translation>
</message>
<message>
<location filename="../src/layout.cpp" line="522"/>
<source>No joystick devices available</source>
<translation>Geen joysticks beschikbaar</translation>
</message>
<message>
<location filename="../src/layout.cpp" line="523"/>
<source>No joystick devices are currently available to configure.
Please plug in a gaming device and select
&quot;Update Joystick Devices&quot; from the popup menu.</source>
<translation>Er zijn geen in te stellen joysticks beschikbaar.
Koppel een apparaat aan en kies
&quot;Zoeken naar joysticks&quot; in het pop-upmenu.</translation>
</message>
<message>
<location filename="../src/layout.cpp" line="583"/>
<source>[NO LAYOUT]</source>
<translation>[GEEN INDELING]</translation>
</message>
</context>
<context>
<name>QuickSet</name>
<message>
<location filename="../src/quickset.cpp" line="7"/>
<source>Set %1</source>
<translation>%1 instellen</translation>
</message>
<message>
<location filename="../src/quickset.cpp" line="13"/>
<source>Press any button or axis and
you will be prompted for a key.</source>
<translation>Druk op een knop of as om
gevraagd te worden om een toets.</translation>
</message>
<message>
<location filename="../src/quickset.cpp" line="15"/>
<source>Done</source>
<translation>Klaar</translation>
</message>
<message>
<location filename="../src/quickset.cpp" line="52"/>
<source>%1, positive</source>
<translation>%1, positief</translation>
</message>
<message>
<location filename="../src/quickset.cpp" line="52"/>
<source>%1, negative</source>
<translation>%1, negatief</translation>
</message>
</context>
<context>
<name>main</name>
<message>
<location filename="../src/main.cpp" line="74"/>
<source>Couldn&apos;t create the QJoyPad save directory</source>
<translation>Kan geen map creëren voor het opslaan van QJoyPad-instellingen</translation>
</message>
<message>
<location filename="../src/main.cpp" line="75"/>
<source>Couldn&apos;t create the QJoyPad save directory: %s</source>
<translation>Kan geen map creëren voor het opslaan van QJoyPad-instellingen: %s</translation>
</message>
<message>
<location filename="../src/main.cpp" line="106"/>
<source>%1
Usage: %2 [--device=&quot;/device/path&quot;] [--notray|--force-tray] [&quot;layout name&quot;]
Options:
-h, --help Print this help message.
-d, --device=PATH Look for joystick devices in PATH. This should
be something like &quot;/dev/input&quot; 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&apos;t support this feature.
-u, --update Force a running instance of QJoyPad to update its
list of devices and layouts.
&quot;layout name&quot; Load the given layout in an already running
instance of QJoyPad, or start QJoyPad using the
given layout.
</source>
<translation>%1
Gebruik: %2 [--device=&quot;/Apparaat/Pad&quot;] [--notray|--force-tray] [&quot;Indelingsnaam&quot;]
Opties:
-h, --help Toont deze hulptekst.
-d, --device=PAD Zoek naar joysticks in het opgegeven pad. Dit moet zoiets als
&quot;/dev/input&quot; 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.
&quot;indelingsnaam&quot; Laad de opgegeven indeling in een actief
QJoyPad-proces of start QJoyPad met de opgegeven
indeling.
</translation>
</message>
<message>
<location filename="../src/main.cpp" line="129"/>
<source>Not a directory</source>
<translation>Is geen map</translation>
</message>
<message>
<location filename="../src/main.cpp" line="130"/>
<source>Path is not a directory: %1</source>
<translation>Het pad is geen map: %1</translation>
</message>
<message>
<location filename="../src/main.cpp" line="149"/>
<source>Illeagal argument.
See `%1 --help` for more information
</source>
<translation>Ongeldig argument.
Bekijk `%1 --help` voor meer informatie
</translation>
</message>
<message>
<location filename="../src/main.cpp" line="160"/>
<source>Too many arguments.
See `%1 --help` for more information
</source>
<translation>Te veel argumenten.
Bekijk `%1 --help` voor meer informatie
</translation>
</message>
<message>
<location filename="../src/main.cpp" line="202"/>
<source>Instance Error</source>
<translation>Procesfout</translation>
</message>
<message>
<location filename="../src/main.cpp" line="203"/>
<source>There is already a running instance of QJoyPad; please close
the old instance before starting a new one.</source>
<translation>Er draait al een proces van QJoyPad. Breek het andere proces
af voordat je een nieuw proces start.</translation>
</message>
<message>
<location filename="../src/main.cpp" line="231"/>
<source>System tray isn&apos;t loading</source>
<translation>Systeemvak laad niet</translation>
</message>
<message>
<location filename="../src/main.cpp" line="232"/>
<source>Waited more than 20 seconds for the system tray to load. Giving up.</source>
<translation>Er is meer dan 20 seconden gewacht op het systeemvak. Actie afgebroken.</translation>
</message>
</context>
</TS>