finishing up repo migration

git-svn-id: svn://svn.code.sf.net/p/qjoypad/code/trunk@80 c05e91a0-76c8-4ec0-b377-ef19ce7cc080
This commit is contained in:
John Toman
2009-05-26 00:45:05 +00:00
committed by virtuoussin13
commit 1cc6e9087e
59 changed files with 6563 additions and 0 deletions

9
INSTALL.txt Normal file
View File

@ -0,0 +1,9 @@
For a quick install, just follow these steps:
tar -xzvf qjoypad-3.?.tgz
cd qjoypad-3.?/src
./config
make
make install
If those steps don't work for you, give the README a look!

340
LICENSE.txt Normal file
View File

@ -0,0 +1,340 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Library General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Library General
Public License instead of this License.

920
README.txt Normal file
View File

@ -0,0 +1,920 @@
QJoyPad 3 Documentation
Distributed with QJoyPad 3.4; available online at
http://qjoypad.sourceforge.net/doc/doc_index.html
Nathan Gaylinn
wren42@users.sourceforge.net
http://qjoypad.sourceforge.net
_________________________________________________________
Table of Contents
1. Introduction
1.1. What is QJoyPad?
1.2. What's it good for?
1.3. Features
2. Getting Started
2.1. Requirements
2.2. Installation
3. Using QJoyPad
3.1. The Tray Icon
3.2. The Popup Menu
3.3. The Setup Dialog
3.3.1. The Layout Selection combo box
3.3.2. The Add button
3.3.3. The Remove button
3.3.4. The Update button
3.3.5. The Revert button
3.3.6. The Joystick buttons
3.3.7. The Joystick Component buttons
3.3.8. The Clear button
3.3.9. Quick Set
3.4. Configuring axes
3.4.1. The Axis Position Indicator
3.4.2. Making an axis "Gradient"
3.4.3. Switching between keyboard and mouse control
3.4.4. Adjusting mouse speed
3.4.5. Setting keys
3.4.6. Throttle Settings
3.5. Configuring buttons
3.5.1. Choosing a key / mouse button
3.5.2. Making a button "Sticky"
3.5.3. Using Rapid Fire
3.6. Command-line use and scripting
4. Layout Files
5. Problems
5.1. I can't get my game controller to work in Linux;
will QJoyPad help?
5.2. Joystick recognition
5.2.1. QJoyPad says it can't find any joysticks?
5.2.2. QJoyPad isn't showing all of my joysticks.
5.2.3. My joystick has more/fewer buttons/axes than
that!
5.3. Joystick adjustment
5.3.1. Why does it say I'm moving if I'm not?
5.3.2. I keep going in two directions at once
instead of just one!
5.3.3. I'm pushing up, but nothing's happening!
5.4. QJoyPad won't start!
5.5. I have two versions of QJoyPad open at once and
they're getting in each other's way!
5.6. I'm getting strange errors when I change layouts;
what's wrong?
5.7. This program only works in XWindows?
5.8. But my window manager doesn't HAVE a system tray!
5.9. I hate the QJoyPad icon. Is there any way to change
it?
5.10. Why do I have to tell QJoyPad to "update joystick
devices"? Why can't it do that on its own?
5.11. When QJoyPad checks for new joysticks, it doesn't
find mine!
5.12. Why are both Up and Down treated as the same axis?
5.13. All of this is too complicated. Why isn't there a
button for Up?
5.14. Features and suggestions
5.14.1. Why can't I click with an axis, or move the
mouse with a button?
5.14.2. Why doesn't QJoyPad do _____?
6. Credits
7. This software is GPL!
_________________________________________________________
Chapter 1. Introduction
1.1. What is QJoyPad?
QJoyPad is a convenient little program with a QT interface
that converts movement and button presses on a gamepad or
joystick into key presses, mouse clicks, and mouse movement in
XWindows. It should work on almost every Linux system and with
any Linux-supported gaming device.
_________________________________________________________
1.2. What's it good for?
QJoyPad lets you play any XWindows game that uses input from
the keyboard and mouse with a joystick device, even if the
game doesn't normally have joystick support. In addition, it's
a convenient companion for emulation software as it prevents
the need for extra controller plugins and can remember
multiple saved layouts. Also, QJoyPad can quickly swap between
layouts whenever you change games, so you'll always have the
controls right where you want them instead of compromising for
the game's defaults or the settings you find most useful in
other games. Now with version 3, QJoyPad also supports
features like rapid fire and sticky buttons (see Section
3.5.2) that can improve your gaming experience.
Not a gamer? Then QJoyPad can still be pretty useful if you
would find it more comfortable or convenient to control your
computer with a joystick or game pad. It may be designed with
gaming in mind, but it's a useful program for virtually any
purpose.
_________________________________________________________
1.3. Features
- Incorporates your gaming devices into any XWindows program
- Move and click the mouse with your joystick
- Auto-detects how many joysticks you have and how many
buttons and axes each supports
- Can detect joystick devices on the fly without restarting
- Support for devices with more than two axes
- Save as many layouts as you want and switch between them
quickly
- Swap layouts on the fly from the command line or from a
script
- Share layout files with your friends or even edit them by
hand for greater control
- Color cues quickly show you which buttons you're pressing
and which joystick you're using
- Set or reset all the keys at once in a flash
- Adjust the sensitivity of every axis independently
- Quietly hides in your system tray, running in the
background without taking up space
- For window managers without a system tray, QJoyPad can run
without the tray icon.
- Make an axis "Gradient" so that a light push does a little
and a harder push does more
- Support for throttle controls
- Make a button "Sticky" if you don't feel like holding it
down all the time
- Turn on Rapid Fire so you don't wear out your gamepad!
_________________________________________________________
Chapter 2. Getting Started
2.1. Requirements
- A Linux computer and a Linux-compatible gaming device
- A Linux kernel with joystick support (see the Linux Kernel
HOWTO [http://www.linuxdocs.org/HOWTOs/Kernel-HOWTO.html]
and the Linux joystick driver website
http://atrey.karlin.mff.cuni.cz/~vojtech/joystick/)
- XWindows (see www.xfree86.org)
- Trolltech's QT (see www.trolltech.com)
_________________________________________________________
2.2. Installation
Installing QJoyPad should be a quick and painless process. The
basic procedure is:
./config
make
make install
however, there are some settings that might need to be
changed.
1. Device directory: By default, QJoyPad will look for
joystick devices in /dev/input, but if your system puts
them somewhere else, you'll need to run ./config with the
argument --devdir=DIR, where DIR is where your joystick
devices reside. For instance, if your joystick devices are
/dev/js0, /dev/js1, etc., instead of running ./config, run
./config --devdir="/dev"
2. Install directory: By default, QJoyPad will try to put a
copy of itself in /usr/local/bin, some icons in
/usr/local/share/pixmaps, and this readme in
/usr/local/doc/qjoypad3 so that they will be accessible to
all users. If you want these files to go somewhere other
than /usr/local (or if you don't have permission to write
to /usr/local), you'll need to pass the argument
--prefix=DIR to ./config. For example, if you wanted to
install QJoyPad just for yourself in your home directory,
you could run ./config --prefix="/home/user" instead of
./config.
3. Use Plain Keys: Normally, QJoyPad doesn't use standard
XWindows key names to describe your keyboard, but instead
uses names that look nicer and are easier to recognize.
For instance, instead of "KP_Begin", "Prior", and
"Shift_L", QJoyPad uses "KP 5", "PageDown", and "L Shift".
If you think generating these names is a waste of
processor power, or if you don't think you're getting the
right name for the key you're pressing, pass the argument
--plain_keys to ./config and QJoyPad will just use the
XWindows default names.
Of course, you can mix use as many of these options at once as
you like. For instance ./config --devdir="/dev"
--prefix="/home/user" is completely valid.
_________________________________________________________
Chapter 3. Using QJoyPad
3.1. The Tray Icon
QJoyPad 3 is centered around the idea of a "tray icon", a
little icon that usually sits on your taskbar, out of the way;
when you first run QJoyPad, this is how it will be, just an
icon. If your window manager doesn't support system tray
icons, then you'll see QJoyPad as a tiny 24x24 window floating
around like any other window (see Section 5.8 ). since this
might be hard to work with, QJoyPad (starting with version
3.3) gives you the option of having a larger icon to work
with; just run qjoypad --notray and QJoyPad will use a larger
floating icon instead of a system tray icon.
By right clicking on the QJoyPad icon (it should look like an
old gamepad), you will get a pop-up menu that lets you switch
layouts (when you first install QJoyPad, there will be no
layouts available) and see some important information. To add
or modify layouts, left click the icon to open the Setup
Dialog.
_________________________________________________________
3.2. The Popup Menu
When you right click the QJoyPad icon, a menu should pop up.
The top of this menu shows you which joystick devices are
currently available (see Section 5.2 if not all your devices
are listed). Below that are the options to update the layout
list or the joystick devices; use these if you have just put a
new layout in ~/.qjoypad3 by hand or if you've plugged in a
new joystick device. Below even farther is a list of the
available layouts and the option to quit.
_________________________________________________________
3.3. The Setup Dialog
The following sections describe the parts of the Setup Dialog
going from the top down and from left to right.
_________________________________________________________
3.3.1. The Layout Selection combo box
At the top of the Setup Dialog is a combo box that says [NO
LAYOUT] to begin with, but as you add new layouts it will
serve as a drop-down list of all the layouts available to you.
_________________________________________________________
3.3.2. The Add button
The Add button adds a new layout to the list, asking you for a
meaningful name. Make the name short, simple, and easy to
remember, just in case you ever want to load the new layout
from the command line. You can use any name you like that
would be a legal filename on your computer (see Chapter 4 for
details.).
_________________________________________________________
3.3.3. The Remove button
The Remove button deletes the layout currently selected in the
combo box, losing it forever.
_________________________________________________________
3.3.4. The Update button
The Update button saves how the keys are currently set to the
current layout. Use this to make changes to an already-defined
layout. Don't forget to use Update to save any changes you
make before quitting or switching to another layout, or all
the changes will be forgotten!
_________________________________________________________
3.3.5. The Revert button
The Revert button does about the opposite of Update. If you've
gone and changed the keys around, pressing Revert will return
them to how they are saved in the current layout.
_________________________________________________________
3.3.6. The Joystick buttons
Immediately below the Add, Remove, Update, and Revert buttons,
there are several buttons labeled Joystick 1, Joystick 2, etc.
that serve as tabs so you can switch between different
controllers to set keys. Whichever one of these buttons is
pressed is the controller you are currently editing. Pressing
any button or moving any axis on a given controller will make
its associated button flash blue to let you know which it is.
_________________________________________________________
3.3.7. The Joystick Component buttons
Beneath the Joystick Buttons is a large pile of buttons
representing every axis and button on your controller.
Whenever you move the axis or push the button that one of
these buttons represents, it will flash blue so that you know
which it is. To setup any of these, just click on the
appropriate button and a dialog will pop up to let you choose
your settings.
_________________________________________________________
3.3.8. The Clear button
The Clear button resets all the axes and buttons to nothing,
essentially rendering the joystick disabled. From here it's
easy enough to set the buttons you need, starting from a clean
slate.
_________________________________________________________
3.3.9. Quick Set
The Quick Set button does exactly what you'd expect, it lets
you set all the buttons and axes quickly! When you click it,
it brings up a little window with a Done button, and until you
click Done it's watching the controller. Whenever you press a
button or move an axis, it will ask you which button you want
associated with that movement. You can't set all the extra
options this way, but it's much faster than going through all
the dialogs!
_________________________________________________________
3.4. Configuring axes
In QJoyPad 2, you were allowed one key to be assigned to each
of four directions, Up, Down, Left, and Right. In version 3,
there is support for many axes and each one can do fancier
things than just press a key. Unfortunately, since different
controllers do things differently, it's not as easy as Up,
Down, Left, and Right. Up-Down is an axis, Left-Right is an
axis, and if you have a nicer controller, you might have many
more axes on top of that.
The first step in configuring axes is to figure out which one
you want to set. If you have a joystick, try moving it around
and seeing which buttons flash blue on the QJoyPad Setup
Dialog. If you have a gamepad, try pressing different buttons
on the Directional-Pad or moving around any mini joystick
controls it might have. Once you know which axis you want to
set, click on its associated button to open the Set Axis
dialog.
_________________________________________________________
3.4.1. The Axis Position Indicator
In the middle of this dialog, you will see a white bar,
divided in two, that represents the current position of the
axis you're editing. Try moving that axis to see how it works.
This is so you know which direction is considered "positive"
and which is "negative"; it might not be what you'd expect. If
this axis is a D-Pad, then it is either off or on, but most
other axes are sensitive to how far they are depressed and a
colored bar here will show you how far it is at the moment.
Along the white bar, you will also see small blue and red tabs
that you can drag. These adjust the "Dead Zone" and the
"Extreme Zone" of the axis. When the colored bar representing
the axis' position passes one of the blue markers, the bar
will turn blue meaning that when the axis is this far QJoyPad
will consider it moved, and when the bar passes one of the red
markers it will turn red and QJoyPad will consider that axis
fully depressed. When the bar is gray, that means that you
haven't moved the axis out of its Dead Zone and QJoyPad is
ignoring its movement. To adjust where the Dead and Extreme
Zones are, just slide the blue and red markers to where you
think they should be.
You probably won't need to adjust the sensitivity unless you
are having trouble getting QJoyPad to generate key presses
when you want it to (see Section 5.3).
_________________________________________________________
3.4.2. Making an axis "Gradient"
On the upper half of this dialog, you will see a checkbox
marked Gradient. Checking this box means that instead of just
generating one key press when the axis is moved, QJoyPad will
start flickering that key on and off as soon as the axis is
out of the Dead Zone (when the colored bar turns blue). How
far the axis is pushed determines what percent of the time the
simulated key will be depressed. As soon as the axis enters
its Extreme Zone (when the colored bar turns red), the key
will be down 100% of the time. Making an axis Gradient is
useful if you want to use it as an accelerator in a game so
how fast you go is controlled by how far the axis is moved.
Also, it's nice to use this when the axis is set to move the
mouse because it can give you finer control of the mouse when
you push the axis just a little but still let you move quickly
when you push it all the way.
_________________________________________________________
3.4.3. Switching between keyboard and mouse control
On the upper half of the dialog, there is a combo box that
lets you choose between keyboard control and mouse control.
There are four different mouse options that let you choose
whether the mouse will move vertically (Up-Down) when the axis
moves or horizontally (Left-Right). You can also reverse the
direction of the mouse if you want moving the axis up to move
the mouse down or visa versa.
Tip
Usually you want an axis to be Gradient if it's going to move
the mouse.
_________________________________________________________
3.4.4. Adjusting mouse speed
When using one of the mouse modes, you can set the speed of
the mouse by adjusting the number in the upper right corner.
_________________________________________________________
3.4.5. Setting keys
When using keyboard mode, you can set which key corresponds to
which direction of the axis by clicking the buttons
immediately below the Axis Position Indicator. The one on the
left will be pressed when the axis is moved in the negative
direction (when the colored bar is on the left side) and the
one on the right when it is in the positive direction (when
the colored bar is on the right side).
_________________________________________________________
3.4.6. Throttle Settings
Between these two buttons is another combo box that changes
the throttle settings. This is meant for gamepads which have a
specific type of throttle control. What it does is instead of
having two keys for when the axis is positive or negative, it
has just one and treats the way the axis moves differently. In
one of the throttle modes, the axis will be considered
centered when it is all the way to one direction or the other.
_________________________________________________________
3.5. Configuring buttons
Similarly to the buttons corresponding to axes in the Setup
Dialog, the ones corresponding to the buttons on your
controller also light up to let you know which is which. To
figure out which button you want, press it on the game device
and then click on the button on screen that flashed. A small
settings dialog will pop up.
_________________________________________________________
3.5.1. Choosing a key / mouse button
At the top of this dialog is a button that you can click to
set which key or mouse button you want to associate with this
button on your controller. Just click on it, and the rest
should be self-explanatory.
_________________________________________________________
3.5.2. Making a button "Sticky"
Below this and to the left is a little checkbox marked Sticky.
When a button is set as Sticky, that means that pressing the
button once will make QJoyPad simulate a key press (or mouse
button press) and pressing that button again will make QJoyPad
release the simulated key. This is useful for racing games
where you're almost always pouring on the gas, or for RPGs
that have a button used for run, even though it's always
better to be running. This way, all you have to do is press
the button once and it's like you're holding it down. To let
the button back up, just press it a second time.
_________________________________________________________
3.5.3. Using Rapid Fire
Just next to the Sticky checkbox is another one marked Rapid
Fire. When this is enabled for a button, holding that button
down means that QJoyPad will flicker the associated key very
fast. This is great for space shooters where you want to fire
quickly but you don't want to break your button (or your
thumb!) from pressing over and over again.
Tip
Keep in mind that any button can be set both Sticky AND Rapid
Fire. This is even better for space shooters because this way
all you need to do is press the button once and from then
until you press it again you will be shooting Rapid Fire.
_________________________________________________________
3.6. Command-line use and scripting
Although QJoyPad only works in XWindows, it supports changing
axes on the fly from the command line. If you want to load up
the layout named "Tetris", all you have to do is run:
qjoypad "Tetris"
and one of two things will happen. If QJoyPad isn't currently
open, it will start running and load the "Tetris" layout (this
is case sensitive! see Chapter 4). If QJoyPad is already
running, it will just silently switch to the requested layout.
What's so great about this is it lets you forget about QJoyPad
once you've made all your layouts, and just worry about your
games! It's very easy to write short little shell scripts to
automatically load the layout you need when you start up a
game. For instance, if you wanted to run the game xgalaga++,
using QJoyPad for joystick support, you could create a text
file called run-xgalaga with the following lines in it:
#!/bin/sh
qjoypad "XGalaga" &
xgalaga++
Then with the command "chmod a+x run-xgalaga" you could make
that text file an executable shell script; once that's done,
all you need to to do is execute run-xgalaga and QJoyPad will
load the appropriate layout and your game will start. To use
this script for any other program, just change "XGalaga" to a
different layout name and "xgalaga++" to the name of some
other program and you're done.
_________________________________________________________
Chapter 4. Layout Files
When QJoyPad saves a layout, it creates a file using that
layout's name. Because of this, layout names must also be
valid filenames. This shouldn't be very limiting, it just
means that names can't contain certain special characters such
as '/', '*', etc. Remember that most Linux file systems are
case sensitive, so a layout named "Layout" will be considered
distinct from a layout named "layout". On most modern file
systems, spaces should be okay and there should be no serious
limits on name length.
Whenever you create a new layout, QJoyPad makes a new file
called Name.lyt in ~/.qjoypad3, where Name is the name that
you provided. Whenever you update that layout, it overwrites
that file to reflect your changes, whenever you revert, it
rereads that file, and if you ever remove that layout, it will
erase that file from your hard drive.
The format of these files isn't difficult to figure out, so
you can edit them by hand if you like. The numbers used to
represent keys are standard X11 keycodes.
It's also easy to share QJoyPad layout files; just copy them
from one user's ~/.qjoypad3 directory to another and either
tell QJoyPad to update the layout list by right clicking on
the tray icon, or just restart QJoyPad. If you switch layouts
through the command line, you don't even need to do that.
_________________________________________________________
Chapter 5. Problems
5.1. I can't get my game controller to work in Linux; will QJoyPad
help?
Well, that depends on why you can't get it to work. For the
most part, the answer is "No." QJoyPad can only use joysticks
and gamepads that are recognized by your kernel and that have
the proper drivers loaded. If you can't get your joysticks to
work at all in Linux, then, no, QJoyPad can't help. (you might
want to check out the joystick.txt file included with your
kernel source; if you don't know anything about working with
the kernel, check out the Linux Kernel HOWTO
[http://www.linuxdocs.org/HOWTOs/Kernel-HOWTO.html] )
If your joystick is detected and somewhat working, but you
can't get it to work in specific programs, then QJoyPad just
might be what you're looking for. One of the main reasons I
wrote QJoyPad was because my gamepads simply wouldn't work
right with the input plugins for Linux Playstation emulators,
so I know for a fact that sometimes QJoyPad can work around
specific software issues.
Check out Section 5.2 for some tips for checking if your
joystick is working.
_________________________________________________________
5.2. Joystick recognition
5.2.1. QJoyPad says it can't find any joysticks?
5.2.2. QJoyPad isn't showing all of my joysticks.
5.2.3. My joystick has more/fewer buttons/axes than that!
QJoyPad automatically recognizes your joysticks using the
Linux joystick driver, so all joysticks must be working
properly in Linux before they can be used in QJoyPad. If you
can't see all of your joysticks or if QJoyPad complains it
can't find any, chances are your joystick(s) are not plugged
in or are not properly detected by Linux. If that's not it,
QJoyPad could also be looking for your joysticks in the wrong
directory.
First, double check that your joysticks are plugged in. If
they aren't, plug them, load any modules you might need, and
tell QJoyPad to Update joystick devices with the popup menu
(remember, this menu is only accessible when the Setup Dialog
is closed).
If you're still having trouble, QJoyPad might have been
compiled with the devdir setting pointing to the wrong place.
That option had to be set at compile time, and to change it
you must recompile (see Section 2.2); however, if you don't
want to bother with that, you can specify the location of your
devices as an argument. Using the command "qjoypad --device
/dev/input", for example, will start QJoyPad and tell it to
look for joysticks in /dev/input/js0, /dev/input/js1, etc.
If that doesn't work, then you might want to make sure your
joysticks are working properly. One way to test this is to do
a "cat /dev/input/js0" (or wherever your joystick device is)
and press a few buttons on the controller. If you get a bunch
of crazy characters, it's working. If not, you'll have to
fiddle around with kernel drivers, and should probably look
elsewhere for guidance.
If for some reason QJoyPad is reporting the wrong number of
buttons or axes for your device, that means the Linux joystick
driver is also reporting the wrong number. Unless you can't
get to buttons or axes that you need, this shouldn't be a
problem, but if you want to get the number right, Try using a
different driver or check out the documentation for the one
you're using.
If your joysticks are working, plugged in, and my program is
looking in the right place, then I'm not sure what to tell
you. Unfortunately, I don't have a wealth of different devices
and software setups to test on. If you're really stuck, drop
me a line and I'll see what I can do.
<wren42@users.sourceforge.net>
_________________________________________________________
5.3. Joystick adjustment
5.3.1. Why does it say I'm moving if I'm not?
5.3.2. I keep going in two directions at once instead of just one!
5.3.3. I'm pushing up, but nothing's happening!
Chances are, this means you're using an overly sensitive or
poorly calibrated joystick or your sensitivity settings are
all wrong. Try adjusting the Dead Zone of the axes that are
giving you trouble (move the blue tab in the Axis Edit
dialog), more away from the center if it thinks you're
pressing a button when you aren't, more toward the center if
it thinks you aren't pressing a button when you are. If that
doesn't work, try manually adjusting your joystick (if it has
adjustment knobs/sliders), or try calibrating it with jscal.
_________________________________________________________
5.4. QJoyPad won't start!
There are two reasons why QJoyPad won't start. For one,
QJoyPad won't start is if it's already running! To make sure
QJoyPad doesn't interfere with itself, only one version of
QJoyPad is allowed to run at a time. If you can't see an
already open version, look for the icon in the system tray. If
you really can't find it anywhere, try running "killall
qjoypad" and then "rm -f ~/lock.pid" and then try starting
QJoyPad again. It should work this time.
Finally, QJoyPad won't actually run if one of its arguments is
--h or --help. When it sees one of those arguments, it outputs
usage information to the console and then quits. If you're
running QJoyPad away from a console or want it to run like
normal, don't give one of these arguments.
_________________________________________________________
5.5. I have two versions of QJoyPad open at once and they're getting
in each other's way!
QJoyPad doesn't work well when there are two or more instances
open; for that reason, it uses a file to tell whether or not
it's already running. Every version of QJoyPad has done this,
but in version 3.4, where that file is kept was changed to
make the program more compatible with certain distributions.
If you're seeing two versions of QJoyPad open at once, that
means that either one of those is QJoyPad 3.4 and the other is
an older version, or that you're running an older version of
QJoyPad on a system where you don't have write access to
/var/run. In either case, you should just make sure that you
are running the newest version of QJoyPad and that there are
no other versions installed on your system.
If you really want to keep earlier versions of QJoyPad, that's
fine! Just remember that if you do, it's possible to have two
instancesrunning at once and that that can cause problems.
_________________________________________________________
5.6. I'm getting strange errors when I change layouts; what's wrong?
Those errors show that there is something wrong with the
layout files themselves. This means the files were corrupted,
edited incorrectly, or for some reason QJoyPad didn't save
them right (shouldn't ever happen, never seen it happen, but
nothing's impossible). Unless the file QJoyPad is looking for
is completely missing or mangled, it's quite likely that the
file can be repaired by hand. If you need help with the save
format, just send me an email <wren42@users.sourceforge.net>
and I'll see if I can't help.
If worse comes to worst and you lose a layout file you
created, it shouldn't take you too long to rebuild it from
scratch.
_________________________________________________________
5.7. This program only works in XWindows?
Yep, I'm afraid so. For all of you out there with old Linux
console games that won't run in an xterm, you'll have to try
something else. If you really must find a way, joy2key is a
program that is similar to QJoyPad but without a graphical
interface or many of the fancier features, but which doesn't
have that limitation. Check it out at:
http://interreality.org/~tetron/technology/joy2key.
_________________________________________________________
5.8. But my window manager doesn't HAVE a system tray!
I'm well aware that every Linux setup is different and that
there are a million different window managers that range from
beautiful, feature-full, and bloated to stark, minimalist, and
lightning-fast. Unfortunately, after a few people suggested
that I have a tray icon for the no-gui mode, I realized that
it was a very, very good idea. The new version of QJoyPad is
built up around the system tray conceptually, and to make a
version that doesn't use it would be a lot of work, so for now
I plan to keep things as they are.
However, to accommodate those of you who don't have a system
tray and can't stand that little icon, using the argument
--notray makes a floating icon that is much bigger instead of
the little tray icon. It still behaves exactly as the smaller
icon would, except it is larger and cannot be captured by the
system tray.
_________________________________________________________
5.9. I hate the QJoyPad icon. Is there any way to change it?
Absolutely! Starting with version 3.3, QJoyPad stores its
icons in $PATH/share/pixmaps/qjoypad (where $PATH is the
install path used by given at install time, /usr/local by
default) and actually comes with a few different icons to
choose from. In that directory, there are two files,
icon24.png and icon64.png which correspond to the small and
large icons that qjoypad will use. These files are just links,
and can be relinked to any png image of the appropriate size.
Feel free to switch between the provided icons, change them,
or make your own! QJoyPad should look how you want it to.
_________________________________________________________
5.10. Why do I have to tell QJoyPad to "update joystick devices"?
Why can't it do that on its own?
It can! With the hotplug options of the more recent Linux
kernels, not only is it easy to automatically load the right
modules for a joystick when it is plugged in, but also to
notify QJoyPad and have it update its list. Unfortunately,
this is a little complex, still not available on everyone's
computer, and still in development. If you'd like to get this
setup, I'd love to help you figure things out and perhaps I'll
make it a standard feature of QJoyPad once I have a better
idea of what needs to be done on various systems. Please,
either contact me for help getting started, or send me an
email after you get it working explaining how you did it ;) To
make QJoyPad search for new devices, use the command qjoypad
--update.
_________________________________________________________
5.11. When QJoyPad checks for new joysticks, it doesn't find mine!
When you plug in a joystick, there are certain things that
have to happen for the joystick to become available to
programs like QJoyPad. Mainly, the joystick has to be
recognized and drivers have to be loaded. Even if this process
is automatic on your computer it could take a few seconds, so
if QJoyPad can't find your device right away, try again a few
moments later. If driver modules aren't loaded automatically,
don't forget to load them before you ask QJoyPad to look for
new devices. If you keep having troubles, see Section 5.2.
_________________________________________________________
5.12. Why are both Up and Down treated as the same axis?
That's because they are the same axis. An "axis" on a joystick
(or gamepad) isn't actually a direction, but a dimension. A
standard simple joystick can move along two axes, the X-axis
(side to side) and the Y-axis (up and down); when you move the
stick to the left, you're moving it along the X-axis in the
negative direction, and when you move it to the right you're
moving it in the positive direction along the same axis.
What really matters is that in QJoyPad, every axis represents
two opposing directions and can therefore have two different
keys. I only do it that way because thats how the device
itself works. I'd make the labels a little more intuitive, but
unfortunately what each axis corresponds to changes from
controller to controller and there's no way for me to know
which is which. If you don't know which axis to set for which
direction, move in the direction you want and see which button
lights up, or try using Quick Set instead.
_________________________________________________________
5.13. All of this is too complicated. Why isn't there a button for
Up?
Unfortunately, adding new features means increasing complexity
and making things more confusing. That's just how things go.
If you just want to have one key pressed when you press a
button on your joystick, try using just the quick set feature
of QJoyPad 3. There all you need to do is press what you want
to press on the joystick and then type the key you want that
button to trigger.
Also, if you preferred the simplicity of QJoyPad 2.1, it's
still available and quite functional, it just doesn't have
quite as many options and doesn't use a system tray icon. The
two versions of QJoyPad are compatible and can both be run on
the same computer without getting in each others' way (as long
as you rename one of them so they aren't both called
"qjoypad"), just not at the same time.
_________________________________________________________
5.14. Features and suggestions
5.14.1. Why can't I click with an axis, or move the mouse with a
_________________________________________________________
5.14.2. Why doesn't QJoyPad do _____?
For the sake of my sanity, I didn't program every possible
thing I could imagine someone wanting to do into QJoyPad. I
added in the features that people were asking for and which
made sense, and I set somewhat arbitrary limits on what the
user can and can't do. Why set limits? Because if I didn't the
program would get far too bulky and too time consuming to
write. I tried to draw the line at what I thought was
reasonable use. No, you can't make the mouse click whenever
you move an axis... but why would you want to?
If there's something that you feel QJoyPad should be able to
do that it can't, let me know and I'll considering adding that
in future versions.
_________________________________________________________
Chapter 6. Credits
Thank you to Erich Kitzml<6D>ller, author of xjoypad for the
inspiration to write QJoyPad and for the code that started me
off.
The development team for Psi, the Jabber client, also get a
lot of thanks for writing the tray icon code that I borrowed
and tweaked. Thank you for developing GPL and for helping
other developers! (Check out the Psi Website
[http://psi.affinix.com/])
Thank you also to everyone who has sent me an email about
QJoyPad. Knowing that my program is used and appreciated means
a lot, especially since that's about all I get out of my
programming. Open source is like teaching; it's very important
and means a lot for young and developing programmers, but it's
a time consuming and underpaid profession ;)
Finally, I need to offer a very warm thank you to Mark
Hannessen who graciously donated one Logitech Wingman
Rumblepad to the cause of QJoyPad. Without that, I simply
would not have been able to add support for multiple axes or
throttle controls, so version 3 might have never been made.
Thank you for your interest and for your support, Mark.
_________________________________________________________
Chapter 7. This software is GPL!
Check out LICENSE.txt or http://www.gnu.org/licenses/gpl.txt
for details! The bare bones of it is, this program is
distributed in open-source form so that others may share it
freely, learn from it, or modify it as they see fit. However,
under no circumstances can it be sold!
This code was written entirely by Nathan Gaylinn (excepting
the code used for displaying a tray icon that is adapted from
the Psi source [http://psi.affinix.com/]) but is based on the
idea of xjoypad by Erich Kitzm<7A>ller.
Yay for the power GPL gives to developers!

BIN
icons/gamepad1-24x24.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

BIN
icons/gamepad1-64x64.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

BIN
icons/gamepad2-24x24.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

BIN
icons/gamepad2-64x64.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

BIN
icons/gamepad3-24x24.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
icons/gamepad3-64x64.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

BIN
icons/gamepad4-24x24.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

BIN
icons/gamepad4-64x64.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

30
src/.kdbgrc.qjoypad Normal file
View File

@ -0,0 +1,30 @@
[Breakpoint 0]
Enabled=true
File=layout.cpp
Line=263
Temporary=false
[Breakpoint 1]
Enabled=true
File=moc_layout_edit.cpp
Line=58
Temporary=false
[Breakpoint 2]
Enabled=true
File=layout_edit.cpp
Line=107
Temporary=false
[General]
DebuggerCmdStr=
DriverName=GDB
FileVersion=1
OptionsSelected=
ProgramArgs=
TTYLevel=7
WorkingDirectory=
[Memory]
ColumnWidths=80,0
NumExprs=0

590
src/Makefile Normal file
View File

@ -0,0 +1,590 @@
#############################################################################
# Makefile for building: qjoypad
# Generated by qmake (2.01a) (Qt 4.5.1) on: Mon May 25 00:43:37 2009
# Project: qjoypad.pro
# Template: app
# Command: /usr/bin/qmake -unix -o Makefile qjoypad.pro
#############################################################################
####### Compiler, tools and options
CC = gcc
CXX = g++
DEFINES = -DDEVDIR="" -DICON24="/share/pixmaps/qjoypad/icon24.png" -DICON64="/share/pixmaps/qjoypad/icon64.png" -DQT_NO_DEBUG -DQT_GUI_LIB -DQT_CORE_LIB -DQT_SHARED
CFLAGS = -pipe -march=i686 -mtune=generic -O2 -pipe -Wall -W -D_REENTRANT $(DEFINES)
CXXFLAGS = -pipe -march=i686 -mtune=generic -O2 -pipe -Wall -W -D_REENTRANT $(DEFINES)
INCPATH = -I/usr/share/qt/mkspecs/linux-g++ -I. -I/usr/include/QtCore -I/usr/include/QtGui -I/usr/include -I. -Itrayicon -I. -I.
LINK = g++
LFLAGS = -Wl,-O1 -Wl,-rpath,/usr/lib
LIBS = $(SUBLIBS) -L/usr/lib -lXtst -lQtGui -L/usr/lib -L/usr/X11R6/lib -pthread -lpng -lfreetype -lgobject-2.0 -lSM -lICE -pthread -pthread -lXrender -lfontconfig -lXext -lX11 -lQtCore -lz -lm -pthread -lgthread-2.0 -lrt -lglib-2.0 -ldl -lpthread
AR = ar cqs
RANLIB =
QMAKE = /usr/bin/qmake
TAR = tar -cf
COMPRESS = gzip -9f
COPY = cp -f
SED = sed
COPY_FILE = $(COPY)
COPY_DIR = $(COPY) -r
INSTALL_FILE = install -m 644 -p
INSTALL_DIR = $(COPY_DIR)
INSTALL_PROGRAM = install -m 755 -p
DEL_FILE = rm -f
SYMLINK = ln -sf
DEL_DIR = rmdir
MOVE = mv -f
CHK_DIR_EXISTS= test -d
MKDIR = mkdir -p
####### Output directory
OBJECTS_DIR = ./
####### Files
SOURCES = axis.cpp \
axis_edit.cpp \
axisw.cpp \
button.cpp \
button_edit.cpp \
buttonw.cpp \
event.cpp \
flash.cpp \
icon.cpp \
joypad.cpp \
joypadw.cpp \
joyslider.cpp \
keycode.cpp \
layout.cpp \
layout_edit.cpp \
main.cpp \
quickset.cpp \
getkey.cpp \
trayicon/trayicon.cpp \
trayicon/trayicon_x11.cpp moc_axis.cpp \
moc_axis_edit.cpp \
moc_button.cpp \
moc_button_edit.cpp \
moc_flash.cpp \
moc_icon.cpp \
moc_joypad.cpp \
moc_joypadw.cpp \
moc_keycode.cpp \
moc_layout.cpp \
moc_getkey.cpp \
moc_trayicon.cpp
OBJECTS = axis.o \
axis_edit.o \
axisw.o \
button.o \
button_edit.o \
buttonw.o \
event.o \
flash.o \
icon.o \
joypad.o \
joypadw.o \
joyslider.o \
keycode.o \
layout.o \
layout_edit.o \
main.o \
quickset.o \
getkey.o \
trayicon.o \
trayicon_x11.o \
moc_axis.o \
moc_axis_edit.o \
moc_button.o \
moc_button_edit.o \
moc_flash.o \
moc_icon.o \
moc_joypad.o \
moc_joypadw.o \
moc_keycode.o \
moc_layout.o \
moc_getkey.o \
moc_trayicon.o
DIST = /usr/share/qt/mkspecs/common/g++.conf \
/usr/share/qt/mkspecs/common/unix.conf \
/usr/share/qt/mkspecs/common/linux.conf \
/usr/share/qt/mkspecs/qconfig.pri \
/usr/share/qt/mkspecs/features/qt_functions.prf \
/usr/share/qt/mkspecs/features/qt_config.prf \
/usr/share/qt/mkspecs/features/exclusive_builds.prf \
/usr/share/qt/mkspecs/features/default_pre.prf \
/usr/share/qt/mkspecs/features/release.prf \
/usr/share/qt/mkspecs/features/default_post.prf \
/usr/share/qt/mkspecs/features/warn_on.prf \
/usr/share/qt/mkspecs/features/qt.prf \
/usr/share/qt/mkspecs/features/unix/thread.prf \
/usr/share/qt/mkspecs/features/moc.prf \
/usr/share/qt/mkspecs/features/resources.prf \
/usr/share/qt/mkspecs/features/uic.prf \
/usr/share/qt/mkspecs/features/yacc.prf \
/usr/share/qt/mkspecs/features/lex.prf \
/usr/share/qt/mkspecs/features/include_source_dir.prf \
qjoypad.pro
QMAKE_TARGET = qjoypad
DESTDIR =
TARGET = qjoypad
first: all
####### Implicit rules
.SUFFIXES: .o .c .cpp .cc .cxx .C
.cpp.o:
$(CXX) -c $(CXXFLAGS) $(INCPATH) -o "$@" "$<"
.cc.o:
$(CXX) -c $(CXXFLAGS) $(INCPATH) -o "$@" "$<"
.cxx.o:
$(CXX) -c $(CXXFLAGS) $(INCPATH) -o "$@" "$<"
.C.o:
$(CXX) -c $(CXXFLAGS) $(INCPATH) -o "$@" "$<"
.c.o:
$(CC) -c $(CFLAGS) $(INCPATH) -o "$@" "$<"
####### Build rules
all: Makefile $(TARGET)
$(TARGET): $(OBJECTS)
$(LINK) $(LFLAGS) -o $(TARGET) $(OBJECTS) $(OBJCOMP) $(LIBS)
Makefile: qjoypad.pro /usr/share/qt/mkspecs/linux-g++/qmake.conf /usr/share/qt/mkspecs/common/g++.conf \
/usr/share/qt/mkspecs/common/unix.conf \
/usr/share/qt/mkspecs/common/linux.conf \
/usr/share/qt/mkspecs/qconfig.pri \
/usr/share/qt/mkspecs/features/qt_functions.prf \
/usr/share/qt/mkspecs/features/qt_config.prf \
/usr/share/qt/mkspecs/features/exclusive_builds.prf \
/usr/share/qt/mkspecs/features/default_pre.prf \
/usr/share/qt/mkspecs/features/release.prf \
/usr/share/qt/mkspecs/features/default_post.prf \
/usr/share/qt/mkspecs/features/warn_on.prf \
/usr/share/qt/mkspecs/features/qt.prf \
/usr/share/qt/mkspecs/features/unix/thread.prf \
/usr/share/qt/mkspecs/features/moc.prf \
/usr/share/qt/mkspecs/features/resources.prf \
/usr/share/qt/mkspecs/features/uic.prf \
/usr/share/qt/mkspecs/features/yacc.prf \
/usr/share/qt/mkspecs/features/lex.prf \
/usr/share/qt/mkspecs/features/include_source_dir.prf \
/usr/lib/libQtGui.prl \
/usr/lib/libQtCore.prl
$(QMAKE) -unix -o Makefile qjoypad.pro
/usr/share/qt/mkspecs/common/g++.conf:
/usr/share/qt/mkspecs/common/unix.conf:
/usr/share/qt/mkspecs/common/linux.conf:
/usr/share/qt/mkspecs/qconfig.pri:
/usr/share/qt/mkspecs/features/qt_functions.prf:
/usr/share/qt/mkspecs/features/qt_config.prf:
/usr/share/qt/mkspecs/features/exclusive_builds.prf:
/usr/share/qt/mkspecs/features/default_pre.prf:
/usr/share/qt/mkspecs/features/release.prf:
/usr/share/qt/mkspecs/features/default_post.prf:
/usr/share/qt/mkspecs/features/warn_on.prf:
/usr/share/qt/mkspecs/features/qt.prf:
/usr/share/qt/mkspecs/features/unix/thread.prf:
/usr/share/qt/mkspecs/features/moc.prf:
/usr/share/qt/mkspecs/features/resources.prf:
/usr/share/qt/mkspecs/features/uic.prf:
/usr/share/qt/mkspecs/features/yacc.prf:
/usr/share/qt/mkspecs/features/lex.prf:
/usr/share/qt/mkspecs/features/include_source_dir.prf:
/usr/lib/libQtGui.prl:
/usr/lib/libQtCore.prl:
qmake: FORCE
@$(QMAKE) -unix -o Makefile qjoypad.pro
dist:
@$(CHK_DIR_EXISTS) .tmp/qjoypad1.0.0 || $(MKDIR) .tmp/qjoypad1.0.0
$(COPY_FILE) --parents $(SOURCES) $(DIST) .tmp/qjoypad1.0.0/ && $(COPY_FILE) --parents axis.h axis_edit.h axisw.h button.h button_edit.h buttonw.h constant.h device.h error.h event.h flash.h icon.h joypad.h joypadw.h joyslider.h keycode.h layout.h getkey.h layout_edit.h quickset.h trayicon/trayicon.h .tmp/qjoypad1.0.0/ && $(COPY_FILE) --parents axis.cpp axis_edit.cpp axisw.cpp button.cpp button_edit.cpp buttonw.cpp event.cpp flash.cpp icon.cpp joypad.cpp joypadw.cpp joyslider.cpp keycode.cpp layout.cpp layout_edit.cpp main.cpp quickset.cpp getkey.cpp trayicon/trayicon.cpp trayicon/trayicon_x11.cpp .tmp/qjoypad1.0.0/ && (cd `dirname .tmp/qjoypad1.0.0` && $(TAR) qjoypad1.0.0.tar qjoypad1.0.0 && $(COMPRESS) qjoypad1.0.0.tar) && $(MOVE) `dirname .tmp/qjoypad1.0.0`/qjoypad1.0.0.tar.gz . && $(DEL_FILE) -r .tmp/qjoypad1.0.0
clean:compiler_clean
-$(DEL_FILE) $(OBJECTS)
-$(DEL_FILE) *~ core *.core
####### Sub-libraries
distclean: clean
-$(DEL_FILE) $(TARGET)
-$(DEL_FILE) Makefile
mocclean: compiler_moc_header_clean compiler_moc_source_clean
mocables: compiler_moc_header_make_all compiler_moc_source_make_all
compiler_moc_header_make_all: moc_axis.cpp moc_axis_edit.cpp moc_button.cpp moc_button_edit.cpp moc_flash.cpp moc_icon.cpp moc_joypad.cpp moc_joypadw.cpp moc_keycode.cpp moc_layout.cpp moc_getkey.cpp moc_trayicon.cpp
compiler_moc_header_clean:
-$(DEL_FILE) moc_axis.cpp moc_axis_edit.cpp moc_button.cpp moc_button_edit.cpp moc_flash.cpp moc_icon.cpp moc_joypad.cpp moc_joypadw.cpp moc_keycode.cpp moc_layout.cpp moc_getkey.cpp moc_trayicon.cpp
moc_axis.cpp: constant.h \
axis.h
/usr/bin/moc $(DEFINES) $(INCPATH) axis.h -o moc_axis.cpp
moc_axis_edit.cpp: axis.h \
constant.h \
joyslider.h \
keycode.h \
axis_edit.h
/usr/bin/moc $(DEFINES) $(INCPATH) axis_edit.h -o moc_axis_edit.cpp
moc_button.cpp: keycode.h \
constant.h \
button.h
/usr/bin/moc $(DEFINES) $(INCPATH) button.h -o moc_button.cpp
moc_button_edit.cpp: button.h \
keycode.h \
constant.h \
button_edit.h
/usr/bin/moc $(DEFINES) $(INCPATH) button_edit.h -o moc_button_edit.cpp
moc_flash.cpp: flash.h
/usr/bin/moc $(DEFINES) $(INCPATH) flash.h -o moc_flash.cpp
moc_icon.cpp: constant.h \
icon.h
/usr/bin/moc $(DEFINES) $(INCPATH) icon.h -o moc_icon.cpp
moc_joypad.cpp: button.h \
keycode.h \
constant.h \
axis.h \
joypadw.h \
axisw.h \
flash.h \
axis_edit.h \
joyslider.h \
joypad.h \
error.h \
buttonw.h \
button_edit.h \
quickset.h \
joypad.h
/usr/bin/moc $(DEFINES) $(INCPATH) joypad.h -o moc_joypad.cpp
moc_joypadw.cpp: axisw.h \
axis.h \
constant.h \
flash.h \
axis_edit.h \
joyslider.h \
keycode.h \
joypad.h \
button.h \
joypadw.h \
buttonw.h \
button_edit.h \
quickset.h \
error.h \
joypadw.h
/usr/bin/moc $(DEFINES) $(INCPATH) joypadw.h -o moc_joypadw.cpp
moc_keycode.cpp: constant.h \
keycode.h
/usr/bin/moc $(DEFINES) $(INCPATH) keycode.h -o moc_keycode.cpp
moc_layout.cpp: joypad.h \
button.h \
keycode.h \
constant.h \
axis.h \
joypadw.h \
axisw.h \
flash.h \
axis_edit.h \
joyslider.h \
buttonw.h \
button_edit.h \
quickset.h \
error.h \
device.h \
trayicon/trayicon.h \
icon.h \
layout_edit.h \
layout.h \
layout.h
/usr/bin/moc $(DEFINES) $(INCPATH) layout.h -o moc_layout.cpp
moc_getkey.cpp: constant.h \
getkey.h
/usr/bin/moc $(DEFINES) $(INCPATH) getkey.h -o moc_getkey.cpp
moc_trayicon.cpp: trayicon/trayicon.h
/usr/bin/moc $(DEFINES) $(INCPATH) trayicon/trayicon.h -o moc_trayicon.cpp
compiler_rcc_make_all:
compiler_rcc_clean:
compiler_image_collection_make_all: qmake_image_collection.cpp
compiler_image_collection_clean:
-$(DEL_FILE) qmake_image_collection.cpp
compiler_moc_source_make_all:
compiler_moc_source_clean:
compiler_uic_make_all:
compiler_uic_clean:
compiler_yacc_decl_make_all:
compiler_yacc_decl_clean:
compiler_yacc_impl_make_all:
compiler_yacc_impl_clean:
compiler_lex_make_all:
compiler_lex_clean:
compiler_clean: compiler_moc_header_clean
####### Compile
axis.o: axis.cpp axis.h \
constant.h \
event.h
$(CXX) -c $(CXXFLAGS) $(INCPATH) -o axis.o axis.cpp
axis_edit.o: axis_edit.cpp axis_edit.h \
axis.h \
constant.h \
joyslider.h \
keycode.h
$(CXX) -c $(CXXFLAGS) $(INCPATH) -o axis_edit.o axis_edit.cpp
axisw.o: axisw.cpp axisw.h \
axis.h \
constant.h \
flash.h \
axis_edit.h \
joyslider.h \
keycode.h
$(CXX) -c $(CXXFLAGS) $(INCPATH) -o axisw.o axisw.cpp
button.o: button.cpp button.h \
keycode.h \
constant.h \
event.h
$(CXX) -c $(CXXFLAGS) $(INCPATH) -o button.o button.cpp
button_edit.o: button_edit.cpp button_edit.h \
button.h \
keycode.h \
constant.h
$(CXX) -c $(CXXFLAGS) $(INCPATH) -o button_edit.o button_edit.cpp
buttonw.o: buttonw.cpp buttonw.h \
button.h \
keycode.h \
constant.h \
button_edit.h \
flash.h
$(CXX) -c $(CXXFLAGS) $(INCPATH) -o buttonw.o buttonw.cpp
event.o: event.cpp event.h
$(CXX) -c $(CXXFLAGS) $(INCPATH) -o event.o event.cpp
flash.o: flash.cpp flash.h
$(CXX) -c $(CXXFLAGS) $(INCPATH) -o flash.o flash.cpp
icon.o: icon.cpp icon.h \
constant.h
$(CXX) -c $(CXXFLAGS) $(INCPATH) -o icon.o icon.cpp
joypad.o: joypad.cpp joypad.h \
button.h \
keycode.h \
constant.h \
axis.h \
joypadw.h \
axisw.h \
flash.h \
axis_edit.h \
joyslider.h \
buttonw.h \
button_edit.h \
quickset.h \
error.h
$(CXX) -c $(CXXFLAGS) $(INCPATH) -o joypad.o joypad.cpp
joypadw.o: joypadw.cpp joypadw.h \
axisw.h \
axis.h \
constant.h \
flash.h \
axis_edit.h \
joyslider.h \
keycode.h \
joypad.h \
button.h \
error.h \
buttonw.h \
button_edit.h \
quickset.h
$(CXX) -c $(CXXFLAGS) $(INCPATH) -o joypadw.o joypadw.cpp
joyslider.o: joyslider.cpp joyslider.h \
constant.h
$(CXX) -c $(CXXFLAGS) $(INCPATH) -o joyslider.o joyslider.cpp
keycode.o: keycode.cpp keycode.h \
constant.h \
getkey.h
$(CXX) -c $(CXXFLAGS) $(INCPATH) -o keycode.o keycode.cpp
layout.o: layout.cpp layout.h \
joypad.h \
button.h \
keycode.h \
constant.h \
axis.h \
joypadw.h \
axisw.h \
flash.h \
axis_edit.h \
joyslider.h \
buttonw.h \
button_edit.h \
quickset.h \
error.h \
device.h \
trayicon/trayicon.h \
icon.h \
layout_edit.h
$(CXX) -c $(CXXFLAGS) $(INCPATH) -o layout.o layout.cpp
layout_edit.o: layout_edit.cpp layout_edit.h \
flash.h \
layout.h \
joypad.h \
button.h \
keycode.h \
constant.h \
axis.h \
joypadw.h \
axisw.h \
axis_edit.h \
joyslider.h \
buttonw.h \
button_edit.h \
quickset.h \
error.h \
device.h \
trayicon/trayicon.h \
icon.h
$(CXX) -c $(CXXFLAGS) $(INCPATH) -o layout_edit.o layout_edit.cpp
main.o: main.cpp layout.h \
joypad.h \
button.h \
keycode.h \
constant.h \
axis.h \
joypadw.h \
axisw.h \
flash.h \
axis_edit.h \
joyslider.h \
buttonw.h \
button_edit.h \
quickset.h \
error.h \
device.h \
trayicon/trayicon.h \
icon.h \
layout_edit.h \
event.h
$(CXX) -c $(CXXFLAGS) $(INCPATH) -o main.o main.cpp
quickset.o: quickset.cpp quickset.h \
joypad.h \
button.h \
keycode.h \
constant.h \
axis.h \
joypadw.h \
axisw.h \
flash.h \
axis_edit.h \
joyslider.h \
buttonw.h \
button_edit.h \
error.h \
getkey.h
$(CXX) -c $(CXXFLAGS) $(INCPATH) -o quickset.o quickset.cpp
getkey.o: getkey.cpp getkey.h \
constant.h
$(CXX) -c $(CXXFLAGS) $(INCPATH) -o getkey.o getkey.cpp
trayicon.o: trayicon/trayicon.cpp trayicon/trayicon.h
$(CXX) -c $(CXXFLAGS) $(INCPATH) -o trayicon.o trayicon/trayicon.cpp
trayicon_x11.o: trayicon/trayicon_x11.cpp trayicon/trayicon.h
$(CXX) -c $(CXXFLAGS) $(INCPATH) -o trayicon_x11.o trayicon/trayicon_x11.cpp
moc_axis.o: moc_axis.cpp
$(CXX) -c $(CXXFLAGS) $(INCPATH) -o moc_axis.o moc_axis.cpp
moc_axis_edit.o: moc_axis_edit.cpp
$(CXX) -c $(CXXFLAGS) $(INCPATH) -o moc_axis_edit.o moc_axis_edit.cpp
moc_button.o: moc_button.cpp
$(CXX) -c $(CXXFLAGS) $(INCPATH) -o moc_button.o moc_button.cpp
moc_button_edit.o: moc_button_edit.cpp
$(CXX) -c $(CXXFLAGS) $(INCPATH) -o moc_button_edit.o moc_button_edit.cpp
moc_flash.o: moc_flash.cpp
$(CXX) -c $(CXXFLAGS) $(INCPATH) -o moc_flash.o moc_flash.cpp
moc_icon.o: moc_icon.cpp
$(CXX) -c $(CXXFLAGS) $(INCPATH) -o moc_icon.o moc_icon.cpp
moc_joypad.o: moc_joypad.cpp
$(CXX) -c $(CXXFLAGS) $(INCPATH) -o moc_joypad.o moc_joypad.cpp
moc_joypadw.o: moc_joypadw.cpp
$(CXX) -c $(CXXFLAGS) $(INCPATH) -o moc_joypadw.o moc_joypadw.cpp
moc_keycode.o: moc_keycode.cpp
$(CXX) -c $(CXXFLAGS) $(INCPATH) -o moc_keycode.o moc_keycode.cpp
moc_layout.o: moc_layout.cpp
$(CXX) -c $(CXXFLAGS) $(INCPATH) -o moc_layout.o moc_layout.cpp
moc_getkey.o: moc_getkey.cpp
$(CXX) -c $(CXXFLAGS) $(INCPATH) -o moc_getkey.o moc_getkey.cpp
moc_trayicon.o: moc_trayicon.cpp
$(CXX) -c $(CXXFLAGS) $(INCPATH) -o moc_trayicon.o moc_trayicon.cpp
####### Install
install_target: first FORCE
@$(CHK_DIR_EXISTS) $(INSTALL_ROOT)/bin/ || $(MKDIR) $(INSTALL_ROOT)/bin/
-$(INSTALL_PROGRAM) "$(QMAKE_TARGET)" "$(INSTALL_ROOT)/bin/$(QMAKE_TARGET)"
-strip "$(INSTALL_ROOT)/bin/$(QMAKE_TARGET)"
uninstall_target: FORCE
-$(DEL_FILE) "$(INSTALL_ROOT)/bin/$(QMAKE_TARGET)"
-$(DEL_DIR) $(INSTALL_ROOT)/bin/
install_icons: first FORCE
@$(CHK_DIR_EXISTS) $(INSTALL_ROOT)/share/pixmaps/qjoypad/ || $(MKDIR) $(INSTALL_ROOT)/share/pixmaps/qjoypad/
cp ../icons/* /share/pixmaps/qjoypad; cd /share/pixmaps/qjoypad; ln -sf gamepad4-24x24.png icon24.png; ln -sf gamepad3-64x64.png icon64.png; chmod -R a+r /share/pixmaps/qjoypad
install_doc: first FORCE
@$(CHK_DIR_EXISTS) $(INSTALL_ROOT)/doc/qjoypad3/ || $(MKDIR) $(INSTALL_ROOT)/doc/qjoypad3/
cp ../README.txt ../LICENSE.txt /doc/qjoypad3
install: install_target install_icons install_doc FORCE
uninstall: uninstall_target FORCE
FORCE:

335
src/axis.cpp Normal file
View File

@ -0,0 +1,335 @@
#include "axis.h"
#include "event.h"
#define sqr(a) ((a)*(a))
Axis::Axis( int i ) {
index = i;
isOn = false;
isDown = false;
state = 0;
gradient = false;
toDefault();
tick = 0;
timer = new QTimer(this);
}
Axis::~Axis() {
release();
delete timer;
}
bool Axis::read( QTextStream* stream ) {
// At this point, toDefault has just been called.
//read in a line from the stream, and split it up into individual words
QString input = stream->readLine().toLower();
QRegExp regex("[\\s,]+");
QStringList words = input.split(regex);
//used to assure QString->int conversions worked
bool ok;
//int to store values derived from strings
int val;
//step through each word, check if it's a token we recognize
for ( QStringList::Iterator it = words.begin(); it != words.end(); ++it ) {
if (*it == "maxspeed") {
++it; //move to the next word, which should be the maximum speed.
//if no value was given, there's an error in the file, stop reading.
if (it == words.end()) return false;
//try to convert the value.
val = (*it).toInt(&ok);
//if that worked and the maximum speed is in range, set it.
if (ok && val >= 0 && val <= MAXMOUSESPEED) maxSpeed = val;
//otherwise, faulty input, give up.
else return false;
}
//pretty much the same process for getting the dead zone
else if (*it == "dzone") {
++it;
if (it == words.end()) return false;
val = (*it).toInt(&ok);
if (ok && val >= 0 && val <= JOYMAX) dZone = val;
else return false;
}
//and again for the extreme zone,
else if (*it == "xzone") {
++it;
if (it == words.end()) return false;
val = (*it).toInt(&ok);
if (ok && val >= 0 && val <= JOYMAX) xZone = val;
else return false;
}
//and for the positive keycode,
else if (*it == "+key") {
++it;
if (it == words.end()) return false;
val = (*it).toInt(&ok);
if (ok && val >= 0 && val <= MAXKEY) pkeycode = val;
else return false;
}
//and finally for the negative keycode.
else if (*it == "-key") {
++it;
if (it == words.end()) return false;
val = (*it).toInt(&ok);
if (ok && val >= 0 && val <= MAXKEY) nkeycode = val;
else return false;
}
//the rest of the options are keywords without integers
else if (*it == "gradient") {
gradient = true;
}
else if (*it == "throttle+") {
throttle = 1;
}
else if (*it == "throttle-") {
throttle = -1;
}
else if (*it == "mouse+v") {
mode = mousepv;
}
else if (*it == "mouse-v") {
mode = mousenv;
}
else if (*it == "mouse+h") {
mode = mouseph;
}
else if (*it == "mouse-h") {
mode = mousenh;
}
//we ignore unrecognized words to be friendly and allow for additions to
//the format in later versions. Note, this means that typos will not get
//the desired effect OR produce an error message.
}
//assume that xZone, dZone, or maxSpeed has changed, for simplicity.
//do a few floating point calculations.
adjustGradient();
//if we parsed through all of the words, yay! All done.
return true;
}
void Axis::timerCalled() {
timerTick(++tick);
}
void Axis::write( QTextStream* stream ) {
*stream << "\t" << getName() << ": ";
if (gradient) *stream << "gradient, ";
if (throttle > 0) *stream << "throttle+, ";
else if (throttle < 0) *stream << "throttle-, ";
if (dZone != DZONE) *stream << "dZone " << dZone << ", ";
if (xZone != XZONE) *stream << "xZone " << xZone << ", ";
if (mode == keybd) {
*stream << "+key " << pkeycode << ", "
<< "-key " << nkeycode << "\n";
}
else {
if (gradient) *stream << "maxSpeed " << maxSpeed << ", ";
*stream << "mouse";
if (mode == mousepv)
*stream << "+v\n";
else if (mode == mousenv)
*stream << "-v\n";
else if (mode == mouseph)
*stream << "+h\n";
else if (mode == mousenh)
*stream << "-h\n";
}
}
void Axis::release() {
//if we're pressing a key, let it go.
if (isDown) {
move(false);
isDown = false;
}
}
void Axis::jsevent( int value ) {
//adjust real value to throttle value
if (throttle == 0)
state = value;
else if (throttle == -1)
state = (value + JOYMIN) / 2;
else
state = (value + JOYMAX) / 2;
//set isOn, deal with state changing.
//if was on but now should be off:
if (isOn && abs(state) <= dZone) {
isOn = false;
if (gradient) {
release();
timer->stop();
tick = 0;
}
}
//if was off but now should be on:
else if (!isOn && abs(state) >= dZone) {
isOn = true;
if (gradient) {
duration = (abs(state) * FREQ) / JOYMAX;
connect(timer, SIGNAL(timeout()), this, SLOT(timerCalled()));
timer->start(MSEC);
}
}
//otherwise, state doesn't change! Don't touch it.
else return;
//gradient will trigger movement on its own via timer().
//non-gradient needs to be told to move.
if (!gradient) {
move(isOn);
}
}
void Axis::toDefault() {
release();
gradient = false;
throttle = 0;
maxSpeed = 100;
dZone = DZONE;
tick = 0;
xZone = XZONE;
mode = keybd;
pkeycode = 0;
nkeycode = 0;
downkey = 0;
state = 0;
adjustGradient();
}
bool Axis::isDefault() {
return (gradient == false) &&
(throttle == 0) &&
(maxSpeed == 100) &&
(dZone == DZONE) &&
(xZone == XZONE) &&
(mode == keybd) &&
(pkeycode == 0) &&
(nkeycode == 0);
}
bool Axis::inDeadZone( int val ) {
int value;
if (throttle == 0)
value = val;
else if (throttle == -1)
value = (val + JOYMIN) / 2;
else
value = (val + JOYMAX) / 2;
return (abs(value) < dZone);
}
QString Axis::status() {
QString result = getName() + " : [";
if (mode == keybd) {
if (throttle == 0)
result += "KEYBOARD";
else result += "THROTTLE";
}
else result += "MOUSE";
return result + "]";
}
void Axis::setKey(bool positive, int value) {
if (positive)
pkeycode = value;
else
nkeycode = value;
}
void Axis::timerTick( int tick ) {
if (isOn) {
if (mode == keybd) {
if (tick % FREQ == 0) {
if (duration == FREQ) {
if (!isDown) move(true);
duration = (abs(state) * FREQ) / JOYMAX;
return;
}
move(true);
}
if (tick % FREQ == duration) {
move(false);
duration = (abs(state) * FREQ) / JOYMAX;
}
}
else {
move(true);
}
}
}
void Axis::adjustGradient() {
//create a nice quadratic curve fitting it to the points
//(dZone,0) and (xZone,MaxSpeed)
a = (double) (maxSpeed) / sqr(xZone - dZone);
b = -2 * a * dZone;
c = a * sqr(dZone);
//actual equation for curve is: y = ax^2 + b
//where x is the state of the axis and y is the distance the mouse should move.
}
void Axis::move( bool press ) {
xevent e;
if (mode == keybd) {
//prevent KeyPress-KeyPress and KeyRelease-KeyRelease pairs.
//this would only happen in odd circumstances involving the setup
//dialog being open and blocking events from happening.
if (isDown == press) return;
isDown = press;
if (press) {
e.type = KPRESS;
downkey = (state > 0)?pkeycode:nkeycode;
}
else {
e.type = KREL;
}
e.value1 = downkey;
e.value2 = 0;
}
//if using the mouse
else if (press) {
int dist;
if (gradient) {
//calculate our mouse speed curve based on calculations made in
//adjustGradient()
int absState = abs(state);
if (absState >= xZone) dist = maxSpeed;
else if (absState <= dZone) dist = 0;
else dist = (int) (a*sqr(absState) + b*absState + c);
}
//if not gradient, always go full speed.
else dist = maxSpeed;
//if we're on the negative side of the axis, must compensate for
//squaring and make distance negative.
if (state < 0) dist = -dist;
e.type = WARP;
if (mode == mousepv) {
e.value1 = 0;
e.value2 = dist;
}
else if (mode == mousenv) {
e.value1 = 0;
e.value2 = -dist;
}
else if (mode == mouseph) {
e.value1 = dist;
e.value2 = 0;
}
else if (mode == mousenh) {
e.value1 = -dist;
e.value2 = 0;
}
}
//actually create the event
sendevent(e);
}

94
src/axis.h Normal file
View File

@ -0,0 +1,94 @@
#ifndef AXIS_H
#define AXIS_H
//abs()
#include <stdlib.h>
#include <QTimer>
#include <QTextStream>
#include <QRegExp>
#include <QStringList>
#include "constant.h"
//default and arbitrary values for dZone and xZone
#define DZONE 3000
#define XZONE 30000
//each axis can create a key press or move the mouse in one of four directions.
enum AxisMode {keybd, mousepv, mousenv, mouseph, mousenh};
//represents one joystick axis
class Axis : public QObject {
Q_OBJECT
//so AxisEdit can manipulate fields directly.
friend class AxisEdit;
public:
Axis( int i );
~Axis();
//read axis settings from a stream
bool read( QTextStream* stream );
//write axis settings to a stream
void write( QTextStream* stream );
//releases any pushed buttons and returns to a neutral state
void release();
//pass a message from the joystick device to this axis object
void jsevent( int value );
//revert to default settings
void toDefault();
//True iff currently at defaults
bool isDefault();
QString getName() { return "Axis " + QString::number(index+1);};
//true iff the given value is in the dead zone for this axis.
bool inDeadZone( int val );
//a descriptive string used as a label for the button representing this axis
QString status();
//set the key code for this axis. Used by quickset.
void setKey(bool positive, int value);
//happens every MSEC milliseconds (constant.h)
//uses tick to decide if key events should be generated
void timerTick( int tick );
//recalculates the gradient curve. This should be run every time
//maxSpeed, xZone, or dZone are changed.
void adjustGradient();
protected:
int tick;
//This axis is logically depressed (positive or negative)
//if the axis is gradient, this is true even if it is not
//currently generating a keypress at the instant.
bool isOn;
//which joystick this actually is
int index;
//actually sends key events. Press is true iff the key
//is to be depressed as opposed to released.
virtual void move( bool press );
//is a key currently depressed?
bool isDown;
//variables for calculating quadratic used for gradient mouse axes
double a,b,c;
//actual axis settings:
bool gradient;
int maxSpeed; //0..MAXMOUSESPEED
int throttle; //-1 (nkey), 0 (no throttle), 1 (pkey)
int dZone;//-32767 .. 32767
int xZone;//-32767 .. 32767
AxisMode mode;
//positive keycode
int pkeycode;
//negative keycode
int nkeycode;
//the key that is currently pressed
int downkey;
//the position of the axis, as from jsevent
int state;
//how long a key should stay down when in gradient mode
//note, the key is still clicked at the same pace no matter what,
//this just decides how long it stays down each cycle.
int duration;
QTimer *timer;
public slots:
void timerCalled();
};
#endif

150
src/axis_edit.cpp Normal file
View File

@ -0,0 +1,150 @@
#include "axis_edit.h"
AxisEdit::AxisEdit( Axis* ax )
:QDialog() {
//build the dialog, display current axis settings :)
axis = ax;
setWindowTitle("Set " + axis->getName());
setWindowIcon(QPixmap(ICON24));
//h, v, and v2 are all references to layouts. They are used to refer to
//various layouts as the dialog is built and are not pointing to the same
//thing throughout. This is just because I don't care about the layouts
//after I have placed the widgets within them and there's no reasno to
//keep track of them.
QVBoxLayout* v = new QVBoxLayout(this);
v->setMargin(5);
v->setSpacing(5);
QHBoxLayout* h = new QHBoxLayout();
QVBoxLayout* v2 = new QVBoxLayout();
v2->setMargin(5);
v2->setSpacing(5);
CGradient = new QCheckBox("Gradient", this);
CGradient->setChecked(axis->gradient);
v2->addWidget(CGradient);
CMode = new QComboBox(this);
CMode->insertItem((int)keybd, QString("Keyboard"), QVariant(NULL));
CMode->insertItem((int) mousepv,QString("Mouse (Vert.)"),QVariant(NULL));
CMode->insertItem((int) mousenv, QString("Mouse (Vert. Rev.)"), QVariant(NULL));
CMode->insertItem((int) mouseph, "Mouse (Hor.)", QVariant(NULL));
CMode->insertItem((int)mousenh, QString("Mouse (Hor. Rev.)"), NULL);
CMode->setCurrentIndex( axis->mode );
connect(CMode, SIGNAL(activated(int)), this, SLOT( CModeChanged( int )));
v2->addWidget(CMode);
h->addLayout(v2);
MouseBox = new QFrame(this);
MouseBox->setFrameStyle( QFrame::Box | QFrame::Sunken );
v2 = new QVBoxLayout(MouseBox);
v2->setSpacing(5);
v2->setMargin(5);
//v2->setAutoAdd(true);
QLabel *mouseLabel = new QLabel("Mouse Speed", MouseBox);
v2->addWidget(mouseLabel);
SSpeed = new QSpinBox(MouseBox);
SSpeed->setRange(0,MAXMOUSESPEED);
SSpeed->setSingleStep(1);
SSpeed->setValue(axis->maxSpeed);
v2->addWidget(SSpeed);
h->addWidget(MouseBox);
v->addLayout(h);
Slider = new JoySlider(axis->dZone, axis->xZone, axis->state, this);
v->addWidget(Slider);
KeyBox = new QFrame(this);
KeyBox->setFrameStyle( QFrame::Box | QFrame::Sunken );
h = new QHBoxLayout(KeyBox);
h->setSpacing(5);
h->setMargin(5);
//h->setAutoAdd(true);
BNeg = new KeyButton(axis->getName(),axis->nkeycode,KeyBox);
CThrottle = new QComboBox(KeyBox);
CThrottle->insertItem(0,"Neg. Throttle",QVariant(NULL));
CThrottle->insertItem(1,"No Throttle",QVariant(NULL));
CThrottle->insertItem(2,"Pos. Throttle",QVariant(NULL));
CThrottle->setCurrentIndex(axis->throttle + 1);
connect( CThrottle, SIGNAL( activated( int )), this, SLOT( CThrottleChanged( int )));
BPos = new KeyButton(axis->getName(),axis->pkeycode,KeyBox);
h->addWidget(BNeg);
h->addWidget(CThrottle);
h->addWidget(BPos);
v->addWidget( KeyBox );
h = new QHBoxLayout();
BOkay = new QPushButton("Okay", this);
connect(BOkay, SIGNAL( clicked() ), this, SLOT( accept()));
h->addWidget(BOkay);
BCancel = new QPushButton("Cancel", this);
connect(BCancel, SIGNAL( clicked() ), this, SLOT( reject()));
h->addWidget(BCancel);
v->addLayout(h);
CModeChanged( axis->mode );
CThrottleChanged( axis->throttle + 1 );
}
void AxisEdit::show() {
QDialog::show();
setFixedSize(size());
}
void AxisEdit::setState( int val ) {
Slider->setValue( val );
}
void AxisEdit::CModeChanged( int index ) {
if (index == keybd) {
MouseBox->setEnabled(false);
KeyBox->setEnabled(true);
}
else {
MouseBox->setEnabled(true);
KeyBox->setEnabled(false);
}
}
void AxisEdit::CThrottleChanged( int index ) {
switch (index) {
case 0:
BNeg->setEnabled(true);
BPos->setEnabled(false);
break;
case 1:
BNeg->setEnabled(true);
BPos->setEnabled(true);
break;
case 2:
BNeg->setEnabled(false);
BPos->setEnabled(true);
break;
}
Slider->setThrottle( index - 1 );
}
void AxisEdit::accept() {
//if the gradient status has changed, either request a timer or turn it down.
/*if (axis->gradient) {
if (!CGradient->isChecked()) tossTimer(axis);
}
else {
if (CGradient->isChecked()) takeTimer(axis);
}*/
axis->gradient = CGradient->isChecked();
axis->maxSpeed = SSpeed->value();
axis->throttle = CThrottle->currentIndex() - 1;
axis->dZone = Slider->dZone();
axis->xZone = Slider->xZone();
axis->mode = (AxisMode) CMode->currentIndex();
axis->pkeycode = BPos->getValue();
axis->nkeycode = BNeg->getValue();
axis->adjustGradient();
QDialog::accept();
}

41
src/axis_edit.h Normal file
View File

@ -0,0 +1,41 @@
#ifndef AXIS_EDIT_H
#define AXIS_EDIT_H
//to refer to the axis we're editing
//for building up the dialog we need
#include "axis.h"
#include <QComboBox>
#include <QSpinBox>
#include <QCheckBox>
#include <QLabel>
//for my home-brewed widgets
#include "joyslider.h"
#include "keycode.h"
class AxisEdit : public QDialog {
Q_OBJECT
public:
AxisEdit(Axis* ax);
//show the dialog (modal)
void show();
//set the current state of the axis (adjusts the JoySlider for real time
//notification of the state to the user)
void setState( int val );
protected slots:
//slots for GUI events
void CModeChanged( int index );
void CThrottleChanged( int index );
void accept();
protected:
//the associated Axis that needs to be set.
Axis *axis;
//the important parts of the dialog:
QCheckBox *CGradient;
QComboBox *CMode, *CThrottle;
QFrame *MouseBox, *KeyBox;
QSpinBox *SSpeed;
KeyButton *BNeg, *BPos;
JoySlider *Slider;
QPushButton *BOkay, *BCancel;
};
#endif

38
src/axisw.cpp Normal file
View File

@ -0,0 +1,38 @@
#include "axisw.h"
AxisWidget::AxisWidget( Axis* a, QWidget* parent )
: FlashButton( "",parent) {
axis = a;
ae = NULL;
update();
on = false;
}
void AxisWidget::jsevent( int val ) {
bool newOn = !axis->inDeadZone(val);
if (on != newOn) {
on = newOn;
flash();
}
if (ae != NULL) ae->setState(val);
}
void AxisWidget::update() {
setText( axis->status());
}
void AxisWidget::mouseReleaseEvent( QMouseEvent* e ) {
//create the edit dialog,
ae = new AxisEdit(axis);
//get its input
ae->exec();
//now that it's done, destroy it!
delete ae;
//and remember that it's gone.
ae = NULL;
update();
//release the button. Waiting to do this until the very end has the nice
//effect of keeping the button depressed while the dialog is shown.
FlashButton::mouseReleaseEvent( e );
}

31
src/axisw.h Normal file
View File

@ -0,0 +1,31 @@
#ifndef AXIS_WIDGET_H
#define AXIS_WIDGET_H
#include <QMouseEvent>
//so we can interact with the axis this refers to
#include "axis.h"
//for the FlashButton widget
#include "flash.h"
//so we can edit this axis when the user clicks the button
#include "axis_edit.h"
class AxisWidget : public FlashButton {
public:
AxisWidget( Axis* a, QWidget* parent );
//this is notified on a jsevent so it can flash if necesary.
void jsevent( int val );
//change the text on this button to reflect the axis' current state.
void update();
private:
//to deal with clicking (by creating an AxisEdit dialog)
void mouseReleaseEvent( QMouseEvent* e );
//is this button currently blue?
bool on;
//the axis this refers to
Axis* axis;
//the edit dialog that we pop up on request.
AxisEdit* ae;
};
#endif

178
src/button.cpp Normal file
View File

@ -0,0 +1,178 @@
#include "button.h"
#include "event.h"
Button::Button( int i ) {
index = i;
isButtonPressed = false;
isDown = false;
rapidfire = false;
timer = new QTimer(this);
toDefault();
tick = 0;
}
Button::~Button() {
release();
//delete timer;
}
bool Button::read( QTextStream* stream ) {
// at this point, toDefault() has just been called.
//read in a line of text and break it into words
QString input = stream->readLine().toLower();
QRegExp regex("[\\s,]+");
QStringList words = input.split(regex);
//used to assure correct conversion of QStrings -> ints
bool ok;
//used to receive converted ints from QStrings.
int val;
//go through every word on the line describing this button.
for ( QStringList::Iterator it = words.begin(); it != words.end(); ++it ) {
if (*it == "mouse") {
++it;
if (it == words.end()) return false;
val = (*it).toInt(&ok);
if (ok && val >= 0 && val <= MAXKEY) {
useMouse = true;
mousecode = val;
}
else return false;
}
else if (*it == "key") {
++it;
if (it == words.end()) return false;
val = (*it).toInt(&ok);
if (ok && val >= 0 && val <= MAXKEY) {
useMouse = false;
keycode = val;
}
else return false;
}
else if (*it == "rapidfire") {
rapidfire = true;
}
else if (*it == "sticky") {
sticky = true;
}
}
return true;
}
void Button::write( QTextStream* stream ) {
*stream << "\t" << getName() << ": ";
if (rapidfire) *stream << "rapidfire, ";
if (sticky) *stream << "sticky, ";
*stream << (useMouse?"mouse ":"key ") << (useMouse?mousecode:keycode) << "\n";
}
void Button::release() {
if (isDown) {
click(false);
isDown = true;
}
}
void Button::jsevent( int value ) {
bool newval = (value == 1);
if (sticky) {
//the state of a sticky key only changes on button press, not button release.
if (value == 1) {
isButtonPressed = !isButtonPressed;
}
else return;
}
//if the received event indicates a change in state,
else if (newval != isButtonPressed) {
isButtonPressed = newval; //change state
if (isButtonPressed && rapidfire) {
tick = 0;
connect(timer, SIGNAL(timeout()), this, SLOT(timerCalled()));
timer->start(MSEC);
}
if (!isButtonPressed && rapidfire) {
timer->stop();
if(isDown) {
click(false);
}
tick = 0;
}
}
//otherwise... we don't care. This shouldn't happen.
else return;
//if rapidfire is on, then timer() will do its job. Otherwise we must
//manually triger the key event.
if (!rapidfire) {
click(isButtonPressed);
}
}
void Button::toDefault() {
rapidfire = false;
sticky = false;
useMouse = false;
keycode = 0;
mousecode = 0;
timer->stop();
}
bool Button::isDefault() {
return (rapidfire == false) &&
(sticky == false) &&
(useMouse == false) &&
(keycode == 0) &&
(mousecode == 0);
}
QString Button::status() {
if (useMouse) {
return getName() + " : Mouse " + QString::number(mousecode);
}
else {
return getName() + " : " + QString(ktos(keycode));
}
}
void Button::setKey( bool mouse, int value ) {
if (mouse) {
mousecode = value;
useMouse = true;
}
else {
keycode = value;
useMouse = false;
}
}
void Button::timerTick( int tick ) {
if (isButtonPressed) {
//originally I just clicked true and then false right after, but this
//was not recognized by some programs. I need a delay in between.
if (tick % FREQ == 0) {
click(true);
}
if (tick % FREQ == FREQ / 2) {
click(false);
}
}
}
void Button::click( bool press ) {
if (isDown == press) return;
isDown = press;
xevent click;
//determine which of the four possible events we're sending.
if (press) click.type = useMouse?BPRESS:KPRESS;
else click.type = useMouse?BREL:KREL;
//set up the event,
click.value1 = useMouse?mousecode:keycode;
click.value2 = 0;
//and send it.
sendevent( click );
}
void Button::timerCalled() {
timerTick(++tick);
}

60
src/button.h Normal file
View File

@ -0,0 +1,60 @@
#ifndef BUTTON_H
#define BUTTON_H
#include <QTimer>
#include <QTextStream>
//for getting a key name in status()
#include "keycode.h"
//note that the Button class, unlike the axis class, does not need a release
//function because it releases the key as soon as it is pressed.
class Button : public QObject {
Q_OBJECT
friend class ButtonEdit;
public:
Button( int i );
~Button();
//read from stream
bool read( QTextStream* stream );
//write to stream
void write( QTextStream* stream );
//releases any pushed buttons and returns to a neutral state
void release();
//process an event from the actual joystick device
void jsevent( int value );
//reset default settings
void toDefault();
//True iff is currently using default settings
bool isDefault();
//returns a string representation of this button.
QString getName() { return "Button " + QString::number(index+1);};
//a descriptive string used as a label for the button representing this axis
QString status();
//set the key code for this axis. Used by quickset.
void setKey(bool mouse, int value);
//happens every MSEC (constant.h) milliseconds
void timerTick( int tick );
protected:
//true iff this button is physically depressed.
bool isButtonPressed;
//the index of this button on the joystick
int index;
//actually sends a key press/release
virtual void click( bool press );
//is a simulated key currently depressed?
bool isDown;
int tick;
//button settings
bool rapidfire;
bool sticky;
bool useMouse;
int keycode;
int mousecode; //like keycode, only mousebutton ;)
QTimer *timer;
public slots:
void timerCalled();
};
#endif

66
src/button_edit.cpp Normal file
View File

@ -0,0 +1,66 @@
#include "button_edit.h"
#include <QHBoxLayout>
#include <QVBoxLayout>
ButtonEdit::ButtonEdit(Button* butt)
:QDialog(0) {
setModal(true);
//build the dialog!
button = butt;
setWindowTitle("Set " + button->getName());
setWindowIcon(QPixmap(ICON24));
QVBoxLayout* v = new QVBoxLayout(this);
v->setMargin(5);
v->setSpacing(5);
BKKey = new KeyButton( button->getName(), button->useMouse?button->mousecode:button->keycode, this, true, button->useMouse);
v->addWidget(BKKey);
QHBoxLayout* h = new QHBoxLayout();
CSticky = new QCheckBox("Sticky", this);
CSticky->setChecked(button->sticky);
h->addWidget(CSticky);
CRapid = new QCheckBox("Rapid Fire", this);
CRapid->setChecked(button->rapidfire);
h->addWidget(CRapid);
v->addLayout(h);
h = new QHBoxLayout();
BOkay = new QPushButton("Okay", this);
connect(BOkay, SIGNAL( clicked() ), this, SLOT( accept()));
h->addWidget(BOkay);
BCancel = new QPushButton("Cancel", this);
connect(BCancel, SIGNAL( clicked() ), this, SLOT( reject()));
h->addWidget(BCancel);
v->addLayout(h);
}
void ButtonEdit::show() {
QDialog::show();
setFixedSize(size());
}
void ButtonEdit::accept() {
//if the rapidfire status has changed, either request a timer or turn it down.
/*if (button->rapidfire) {
if (!CRapid->isChecked()) tossTimer(button);
}
else {
if (CRapid->isChecked()) takeTimer(button);
}*/
button->rapidfire = CRapid->isChecked();
button->sticky = (CSticky->isChecked());
//if the user chose a mouse button...
if (BKKey->choseMouse()) {
button->useMouse = true;
button->mousecode = BKKey->getValue();
}
else {
button->useMouse = false;
button->keycode = BKKey->getValue();
}
QDialog::accept();
}

30
src/button_edit.h Normal file
View File

@ -0,0 +1,30 @@
#ifndef BUTTON_EDIT_H
#define BUTTON_EDIT_H
#include <QPushButton>
#include <QCheckBox>
//we need to edit a Button
#include "button.h"
//to get a new key for the button.
#include "keycode.h"
class ButtonEdit : public QDialog {
Q_OBJECT
public:
ButtonEdit(Button* butt);
void show();
protected slots:
void accept();
protected:
Button *button;
KeyButton *BKKey;
QPushButton *BKey, *BMouse, *BOkay, *BCancel;
QPushButton **BMKey;
QCheckBox *CSticky, *CRapid;
};
#endif

30
src/buttonw.cpp Normal file
View File

@ -0,0 +1,30 @@
#include "buttonw.h"
ButtonWidget::ButtonWidget( Button* b, QWidget* parent )
: FlashButton( "", parent) {
button = b;
update();
on = false;
}
void ButtonWidget::jsevent( int val ) {
bool newOn = (val == 1);
if (on != newOn) {
on = newOn;
flash();
}
}
void ButtonWidget::update() {
setText( button->status());
}
void ButtonWidget::mouseReleaseEvent( QMouseEvent* e ) {
ButtonEdit* be = new ButtonEdit(button);
be->exec();
delete be;
update();
FlashButton::mouseReleaseEvent( e );
}

28
src/buttonw.h Normal file
View File

@ -0,0 +1,28 @@
#ifndef BUTTON_WIDGET_H
#define BUTTON_WIDGET_H
//this represents a Button
#include "button.h"
//this can set a button using a ButtonEdit
#include "button_edit.h"
//this IS a FlashButton
#include "flash.h"
#ifdef Bool
#undef Bool
#endif
#include <QMouseEvent>
class ButtonWidget : public FlashButton {
public:
ButtonWidget( Button* b, QWidget* parent);
void jsevent( int val );
//reset the label to match the respective Button's current state.
void update();
private:
void mouseReleaseEvent( QMouseEvent* e );
bool on;
Button* button;
};
#endif

80
src/config Executable file
View File

@ -0,0 +1,80 @@
#!/bin/bash
devdir="/dev/input"
prefix="/usr/local"
plain_keys=""
for arg in $*
do
case $arg in
--help) echo "
Usage: ./config [--devdir=\"dir\"] [--prefix=\"prefix\"] [--help]
Options:
--devdir=DIR Set the path where QJoyPad will look for your joystick
devices to be DIR. If your devices are /dev/js0, /dev/js1,
etc., this should be just \"/dev\". By default, this is
/dev/input.
--prefix=DIR Set the path where QJoyPad and its components will be
installed. By default, this is /usr/local.
--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.
--help Show this message.
"; exit 0;;
--devdir=*) devdir=${arg##*=}
if [[ ! -d $devdir ]]
then
echo "Invalid device directory given: $devdir"
exit 1
fi ;;
--prefix=*) prefix=${arg##*=}
if [[ ! -d $prefix ]]
then
echo "Invalid prefix directory given: $prefix"
exit 1
fi ;;
--plain_keys) plain_keys="PLAIN_KEYS";;
*) echo "Unrecognized argument: \"$arg\". Try ./config --help for help."
esac
done
arg1="DEVDIR=$devdir"
arg2="PREFIX=$prefix"
arg3="DEFINES += $plain_keys"
qmake -makefile "$arg1" "$arg2" "$arg3" qjoypad.pro
echo "
Configuring QJoyPad installation...
------------------------------------------------------------
Device directory: $devdir
-- Devices will be looked for in:
$devdir/js0
$devdir/js1
etc.
Prefix directory: $prefix
-- Files to be installed in:
$prefix/bin
$prefix/doc
$prefix/share/pixmaps"
if [[ -n $plain_keys ]]; then
echo "
-- Using regular XWindows key names.";
fi
echo "
---------------------------------------------------------
If these settings are okay, go ahead and run 'make' and
then 'make install'.
To make changes, run ./config --help for details.
"

29
src/constant.h Normal file
View File

@ -0,0 +1,29 @@
#ifndef JCONST_H
#define JCONST_H
//How many cycles there are per click.
#define FREQ 10
//How many milliseconds per cycle.
#define MSEC 5
//events will be generated every FREQ * MSEC milliseconds. The duration of the
//event can be anywhere between 0 * MSEC and FREQ * MSEC. This means there will
//be FREQ + 1 levels of gradation.
//maximum range of values from joystick driver
#define JOYMAX 32767
#define JOYMIN -32767
//maximum number of defined keys
#define MAXKEY 122
//fastest the mouse can go. Completely arbitrary.
#define MAXMOUSESPEED 5000
#define NAME "QJoyPad 3.4"
#define MOUSE_OFFSET 400
#endif

16
src/device.h Normal file
View File

@ -0,0 +1,16 @@
#ifndef JOY_DEVICE_H
#define JOY_DEVICE_H
#include "joypad.h"
//the purpose of this file is to make device information available to what
//needs it.
//a collection of joysticks currently available on this computer
extern QHash<int, JoyPad*> available;
//a collection of joypad objects representing all the available joysticks
//as well as the ones defined in a layout buy not currently plugged in.
extern QHash<int, JoyPad*> joypads;
#endif

13
src/error.h Normal file
View File

@ -0,0 +1,13 @@
#ifndef JOY_ERROR_H
#define JOY_ERROR_H
#include <qmessagebox.h>
//a nice simple way of throwing up an error message if something goes wrong.
static void error(QString type, QString message ) {
QMessageBox::warning(0,NAME" - " + type,
message, QMessageBox::Ok, Qt::NoButton);
}
#endif

21
src/event.cpp Normal file
View File

@ -0,0 +1,21 @@
#include "event.h"
//this should be initialized by main.cpp as soon as the program starts.
Display* display;
//actually creates an XWindows event :)
void sendevent( xevent e ) {
if (e.value1 == 0 && e.value2 == 0) return;
if (e.type == WARP) {
XTestFakeRelativeMotionEvent(display, e.value1, e.value2, 0);
}
else {
if (e.type == KREL || e.type == KPRESS) {
XTestFakeKeyEvent(display, e.value1, (e.type == KPRESS), 0);
}
else if (e.type == BREL || e.type == BPRESS) {
XTestFakeButtonEvent(display, e.value1, (e.type == BPRESS), 0);
}
}
XFlush(display);
}

22
src/event.h Normal file
View File

@ -0,0 +1,22 @@
#ifndef JEVENT_H
#define JEVENT_H
//for the functions we need to generate keypresses / mouse actions
#include <X11/extensions/XTest.h>
//types of events QJoyPad can create.
//KeyRelease, KeyPress, ButtonRelease, ButtonPress, and MouseMove
enum eventType {KREL, KPRESS, BREL, BPRESS, WARP};
//a simplified event structure that can handle buttons and mouse movements
struct xevent {
eventType type;
int value1; //button, keycode, or x
int value2; //y
};
void sendevent( xevent e );
#endif

99
src/flash.cpp Normal file
View File

@ -0,0 +1,99 @@
#include "flash.h"
//Added by qt3to4:
//Modified here (and in .h) to not have default arguments for 2 and 3.
//This caused an error with a development version of g++ on a Mandrake system
//in Sweden.
FlashButton::FlashButton( QString text, QWidget* parent, QString name )
:QPushButton( text, parent )
{
this->setObjectName(name);
//record the base palette for posterity.
Normal = palette();
//define the palette the button will have when it flashes.
QPalette cg = this->palette();
cg.setCurrentColorGroup(QPalette::Inactive);
cg.setColor(QPalette::Button, HIGHLIGHT);
cg.setColor(QPalette::Light, HIGHLIGHT.light(150));
cg.setColor(QPalette::Midlight, HIGHLIGHT.light(125));
cg.setColor(QPalette::Dark, HIGHLIGHT.dark(200));
cg.setColor(QPalette::Mid, HIGHLIGHT.dark(150));
Flash = cg;
isflash=false;
setAutoDefault( false );
setFocusPolicy(Qt::NoFocus);
}
void FlashButton::flash()
{
emit( flashed( !isflash ) );
if (isflash)
{
setPalette( Normal );
isflash = false;
}
else
{
setPalette( Flash );
isflash = true;
}
}
FlashRadioArray::FlashRadioArray( int count, QString names[], bool horizontal, QWidget* parent)
:QWidget( parent )
{
if (horizontal) {
LMain = new QHBoxLayout( this);
LMain->setMargin(5);
LMain->setSpacing(5);
} else {
LMain = new QVBoxLayout( this);
LMain->setMargin(5);
LMain->setSpacing(5);
}
Buttons = new FlashButton*[count];
for (int i = 0; i < count; i++)
{
Buttons[i] = new FlashButton( names[i], this, "" );
//when any of the buttons is clicked, it calls the same function on this.
connect( Buttons[i], SIGNAL( clicked() ), this, SLOT( clicked() ));
LMain->addWidget(Buttons[i]);
}
Count = count;
State = 0;
Buttons[0]->setDown( true );
}
int FlashRadioArray::getState()
{
return State;
}
void FlashRadioArray::flash( int index )
{
Buttons[index]->flash();
}
void FlashRadioArray::clicked()
{
//go through each button. If it wasn't the button that was just clicked,
//then make sure that it is up. If it WAS the button that was clicked,
//remember that index as the new state.
for (int i = 0; i < Count; i++)
{
if ( Buttons[i] != sender() )
Buttons[i]->setDown( false );
else
{
State = i;
Buttons[i]->setDown( true );
}
}
emit changed( State );
}

77
src/flash.h Normal file
View File

@ -0,0 +1,77 @@
#ifndef FLASH_H
#define FLASH_H
//The color the buttons flash! Feel free to change this.
//The three numbers are all you need to touch, and they
//represent the red, green, and blue values of the color,
//respectively.
#define HIGHLIGHT QColor( 0,0,255 )
//--- --- --- --- End of editable code.
#include <QPushButton>
#include <QPalette>
#include <QBoxLayout>
//A QPushButton that can flash a color
//The color it flashes is defined by HIGHLIGHT
//A FlashButton can now also be set dark
//in the same way that it can flash, but
//a FlashButton can not be dark and flash at the same time.
class FlashButton : public QPushButton
{
Q_OBJECT
public:
FlashButton( QString text, QWidget* parent, QString name = "" );
public slots:
//make the button turn blue if it was gray, or visa versa.
void flash();
signals:
//let the world know when flash() happens!
void flashed( bool on );
private:
//is this currently "flashed" (ie, colored blue)?
bool isflash;
//the normal, unflashed palette
QPalette Normal;
//the colorful flashed palette
QPalette Flash;
};
//An array of flashing mutually-exclusive toggle buttons.
class FlashRadioArray : public QWidget
{
Q_OBJECT
public:
FlashRadioArray( int count, QString names[], bool horizontal, QWidget* parent);
//returns an integer returning the currently selected button.
//First button is 0.
int getState();
public slots:
//flash the button at the given index
void flash( int );
private slots:
//this is what happens when one of the buttons in the array is clicked.
void clicked();
signals:
//happens when the state changes. The int is the new state.
void changed( int );
private:
//how many buttons
int Count;
//which is currently down
int State;
//the array of buttons
FlashButton** Buttons;
//the main layout.
QBoxLayout* LMain;
};
#endif

58
src/getkey.cpp Normal file
View File

@ -0,0 +1,58 @@
#include "getkey.h"
GetKey::GetKey( QString button, bool m )
:QDialog( 0 )
{
//prepare the dialog
mouse = m;
setWindowTitle( "Choose a key" );
setWindowIcon(QIcon(ICON24));
//I'd use a QLabel, but that steals x11Events!
//So, I'll draw the text directly. That means
//I need to resolve the size of the dialog by hand:
Text = "Choose a new key ";
if (mouse) Text += "or mouse button ";
Text += "for " + button;
QRect rect = fontMetrics().boundingRect( Text );
//I calculate the size based on the first line of text, which is longer.
//The fontMetrics function is dumb and would treat the string with a
//newline in it as a continues flow of characters if I did the whole string
//at once.
Text += "\n(Ctrl-X for no key)";
//now I add 20 pixels of padding and double the height to make room for
//two lines.
setFixedSize( QSize( rect.width() + 20, rect.height()*2 + 20 ) );
}
bool GetKey::x11Event( XEvent* e )
{
//keep Qt from closing the dialog upon seeing Esc pressed.
if (e->type == KeyPress) return true;
//On a key press, return the key and quit
//Ctrl+X == [No Key]
if (e->type == KeyRelease) {
if (XKeycodeToKeysym(display,e->xkey.keycode,0) == XK_x ) {
if (e->xkey.state & ControlMask) done( 0 );
else done( e->xkey.keycode );
}
else done( e->xkey.keycode );
return true;
}
//if we're accepting mouse clicks and a mouse button was clicked...
if (mouse && e->type == ButtonRelease) {
done ( e->xbutton.button + MOUSE_OFFSET);
return true;
}
//any other events we will pass on to the dialog. This allows for closing
//the window and easy redrawing :)
return false;
}
void GetKey::paintEvent ( QPaintEvent * ) {
//whenever we need to repaint, draw in our text.
QPainter paint( this );
paint.drawText( rect(), Qt::AlignCenter, Text );
}

28
src/getkey.h Normal file
View File

@ -0,0 +1,28 @@
#include <QDialog>
#include <QPainter>
#include <QPixmap>
#include <QIcon>
#include "constant.h"
#include <X11/Xlib.h>
//The KeySym for "x"
#define XK_x 0x078
extern Display *display;
//a keycode dialog box
class GetKey : public QDialog {
Q_OBJECT
public:
GetKey( QString button, bool m = false );
protected:
//to filter through every event this thing sees, before QT does.
bool x11Event( XEvent* e );
//to avoid focus issues, there is only the dialog widget, all the
//rest is painted on. So, I need to know when to repaint.
void paintEvent ( QPaintEvent * );
private:
//the dialog's message
QString Text;
//does this dialog accept mouse clicks?
bool mouse;
};

33
src/icon.cpp Normal file
View File

@ -0,0 +1,33 @@
#include "icon.h"
FloatingIcon::FloatingIcon( const QPixmap &icon, QMenu *popup, QWidget *parent, const char *name)
: QDialog( parent ) {
this->setObjectName(name);
setWindowTitle(NAME);
QPalette palette;
palette.setBrush(backgroundRole(), QBrush(icon));
setPalette(palette);
//setPaletteBackgroundPixmap(icon);
pop = popup;
setFixedSize(64,64);
}
void FloatingIcon::mousePressEvent( QMouseEvent* e ) {
//if it was the right mouse button,
if (e->button() == Qt::RightButton) {
//bring up the popup menu.
pop->popup( e->globalPos() );
e->accept();
}
else {
//otherwise, treat it as a regular click.
emit clicked();
}
}
void FloatingIcon::closeEvent( QCloseEvent* e ) {
emit closed();
e->accept();
}

25
src/icon.h Normal file
View File

@ -0,0 +1,25 @@
#ifndef JOY_ICON_H
#define JOY_ICON_H
#include <QDialog>
#include <QMenu>
#include <QPixmap>
#include <QMouseEvent>
#include <QCloseEvent>
#include "constant.h"
class FloatingIcon : public QDialog {
Q_OBJECT
public:
FloatingIcon( const QPixmap &icon, QMenu *popup = 0, QWidget *parent = 0, const char *name = 0);
signals:
void closed();
void clicked();
protected:
void mousePressEvent( QMouseEvent* e );
void closeEvent( QCloseEvent* e );
QMenu* pop;
};
#endif

270
src/joypad.cpp Normal file
View File

@ -0,0 +1,270 @@
#include "unistd.h"
#include "joypad.h"
#include <stdio.h>
#include <fcntl.h>
#include <poll.h>
#include <QApplication>
JoyPad::JoyPad( int i, int dev ) {
//remember the index,
index = i;
//load data from the joystick device, if available.
joydevFileHandle = NULL;
if(dev > 0) {
resetToDev(dev);
joydevFileHandle = new QSocketNotifier(dev, QSocketNotifier::Read, this);
connect(joydevFileHandle, SIGNAL(activated(int)), this, SLOT(handleJoyEvents(int)));
}
//there is no JoyPadWidget yet.
jpw = NULL;
}
void JoyPad::resetToDev(int dev ) {
//remember the device file descriptor
joydev = dev;
//read in the number of axes / buttons
axes = 0;
ioctl (joydev, JSIOCGAXES, &axes);
buttons = 0;
ioctl (joydev, JSIOCGBUTTONS, &buttons);
//make sure that we have the axes we need.
//if one that we need doesn't yet exist, add it in.
//Note: if the current layout has a key assigned to an axis that did not
//have a real joystick axis mapped to it, and this function suddenly brings
//that axis into use, the key assignment will not be lost because the axis
//will already exist and no new axis will be created.
for (int i = 0; i < axes; i++) {
if (Axes[i] == 0) Axes.insert(i, new Axis( i ));
}
for (int i = 0; i < buttons; i++) {
if (Buttons[i] == 0) Buttons.insert(i, new Button( i ));
}
struct pollfd read_struct;
read_struct.fd = joydev;
read_struct.events = POLLIN;
char buf[10];
while(poll(&read_struct, 1, 2)!=0) {
printf("reading junk data\n");
read(joydev, buf, 10);
}
setupJoyDeviceListener(dev);
}
void JoyPad::setupJoyDeviceListener(int dev) {
if(joydevFileHandle != NULL) {
delete joydevFileHandle;
}
joydevFileHandle = new QSocketNotifier(dev, QSocketNotifier::Read, this);
connect(joydevFileHandle, SIGNAL(activated(int)), this, SLOT(handleJoyEvents(int)));
}
void JoyPad::toDefault() {
//to reset the whole, reset all the parts.
do
{
QHashIterator<int, Axis*> it( Axes );
while (it.hasNext())
{
it.next();
it.value()->toDefault();
}
} while (0);
do
{
QHashIterator<int, Button*> it( Buttons );
while (it.hasNext())
{
it.next();
it.value()->toDefault();
}
} while (0);
}
bool JoyPad::isDefault() {
//if any of the parts are not at default, then the whole isn't either.
do {
QHashIterator<int, Axis*> it( Axes );
while (it.hasNext())
{
it.next();
if (!it.value()->isDefault()) return false;
}
} while (0);
do {
QHashIterator<int, Button*> it( Buttons );
while (it.hasNext())
{
it.next();
if (!it.value()->isDefault()) return false;
}
} while (0);
return true;
}
bool JoyPad::readConfig( QTextStream* stream ) {
toDefault();
QString word;
QChar dump;
int num;
*stream >> word;
while (word != NULL && word != "}") {
word = word.toLower();
if (word == "button") {
*stream >> num;
if (num > 0) {
*stream >> dump;
if (dump != ':') {
error("Layout file error", "Expected ':', found '" + QString(dump) + "'.");
return false;
}
if (Buttons[num-1] == 0) {
Buttons.insert(num-1,new Button(num-1));
}
if (!Buttons[num-1]->read( stream )) {
error("Layout file error", "Error reading Button " + QString::number(num));
return false;
}
}
else {
stream->readLine();
}
}
else if (word == "axis") {
*stream >> num;
if (num > 0) {
*stream >> dump;
if (dump != ':') {
error("Layout file error", "Expected ':', found '" + QString(dump) + "'.");
return false;
}
if (Axes[num-1] == 0) {
Axes.insert(num-1,new Axis(num-1));
}
if (!Axes[num-1]->read(stream)) {
error("Layout file error", "Error reading Axis " + QString::number(num));
return false;
}
}
}
else {
error( "Layout file error", "Error while reading layout. Unrecognized word: " + word );
return false;
}
*stream >> word;
}
return true;
}
//only actually writes something if this JoyPad is NON DEFAULT.
void JoyPad::write( QTextStream* stream ) {
int i = 0; //use to test if this is default or not.
QString result;
QTextStream* s = new QTextStream(&result, QIODevice::WriteOnly);
*s << getName() << " {\n";
do {
QHashIterator<int, Axis*> it( Axes );
while (it.hasNext()) {
it.next();
if (!it.value()->isDefault()) {
it.value()->write( s );
++i;
}
}
} while (0);
QHashIterator<int, Button*> it( Buttons );
while (it.hasNext()) {
it.next();
if (!it.value()->isDefault()) {
it.value()->write( s );
++i;
}
}
if (i > 0) {
*stream << result << "}\n\n";
}
}
void JoyPad::release() {
do {
QHashIterator<int, Axis*> it( Axes );
while (it.hasNext()) {
it.next();
it.value()->release();
}
} while (0);
do {
QHashIterator<int, Button*> it( Buttons );
while (it.hasNext()) {
it.next();
it.value()->release();
}
} while (0);
}
void JoyPad::jsevent( js_event msg ) {
//if there is a JoyPadWidget around, ie, if the joypad is being edited
if (jpw != NULL) {
//tell the dialog there was an event. It will use this to flash
//the appropriate button, if necesary.
jpw->jsevent(msg);
return;
}
//if the dialog is open, stop here. We don't want to signal ourselves with
//the input we generate.
if (qApp->activeWindow() != 0 && qApp->activeModalWidget() != 0) return;
//otherwise, lets create us a fake event! Pass on the event to whichever
//Button or Axis was pressed and let them decide what to do with it.
if (msg.type & JS_EVENT_AXIS) {
printf("passing on an axis event\n");
printf("DEBUG: %d %d\n", msg.number, msg.value);
Axes[msg.number]->jsevent(msg.value);
}
else {
printf("passing on a button event\n");
printf("DEBUG: %d %d\n", msg.number, msg.value);
Buttons[msg.number]->jsevent(msg.value);
}
}
JoyPadWidget* JoyPad::widget( QWidget* parent, int i) {
//create the widget and remember it.
jpw = new JoyPadWidget(this, i, parent);
return jpw;
}
void JoyPad::handleJoyEvents(int fd) {
js_event msg;
int len;
len = read( joydev, &msg, sizeof(js_event));
//if there was a real event waiting,
if (len == (int) sizeof(js_event)) {
//pass that event on to the joypad!
jsevent(msg);
} else {
printf("NOOOOOOO\n");
}
//sleep for a moment. This is just to keep us from throwing all the
//available processer power into madly checking for new events.
//usleep(10000);
}
void JoyPad::releaseWidget() {
//this is how we know that there is no longer a JoyPadWidget around.
jpw = NULL;
}
void JoyPad::unsetDev() {
close(joydev);
joydev = -1;
if(joydevFileHandle != NULL) {
delete joydevFileHandle;
}
}

80
src/joypad.h Normal file
View File

@ -0,0 +1,80 @@
#ifndef JOYPAD_H
#define JOYPAD_H
//parts of the joypad
#include "button.h"
#include "axis.h"
//the widget that will edit this
#include "joypadw.h"
//for raising errors
#include "error.h"
//for actually interacting with the joystick devices
#include <linux/joystick.h>
#include <fcntl.h>
#include <unistd.h>
#include <QTextStream>
#include <QHash>
#include <QSocketNotifier>
class JoyPadWidget;
//represents an actual joystick device
class JoyPad : public QObject{
Q_OBJECT
friend class JoyPadWidget;
friend class QuickSet;
public:
void setupJoyDeviceListener(int dev);
JoyPad( int i, int dev );
//read from a stream
bool readConfig( QTextStream* stream );
//write to a stream
void write( QTextStream* stream );
//release any pushed buttons and return to a neutral state
void release();
//handle an event from the joystick device this is associated with
void jsevent( js_event msg );
//reset to default settings
void toDefault();
//true iff this is currently at default settings
bool isDefault();
//release the connection to the real joystick
void unsetDev();
//read the dimensions on the real joystick and use them
void resetToDev( int dev );
//generates a name ("Joystick 1")
QString getName() { return "Joystick " + QString::number(index+1);};
//it's just easier to have these publicly available.
int joydev; //the actual file descriptor to the joystick device
int axes; //the number of axes available on this device
int buttons; //the number of buttons
//request the joypad to make a JoyPadWidget. We create them this way
//so that the joypad is always aware when it has a widget active.
JoyPadWidget* widget(QWidget* parent, int i);
//called when the joypad is no longer being edited.
void releaseWidget();
protected:
//lookup axes and buttons. These are dictionaries to support
//layouts with different numbers of axes/buttons than the current
//devices. Note that with the current layout settings, the defined
//buttons that don't actually exist on the device may not be contiguous.
QHash<int, Axis*> Axes;
QHash<int, Button*> Buttons;
//the index of this device (devicenum)
int index;
//the widget that edits this. Mainly I keep track of this to know if
//the joypad is currently being edited.
JoyPadWidget* jpw;
QSocketNotifier *joydevFileHandle;
public slots:
void handleJoyEvents(int fd);
};
#endif

102
src/joypadw.cpp Normal file
View File

@ -0,0 +1,102 @@
#include "joypadw.h"
//Added by qt3to4:
JoyPadWidget::JoyPadWidget( JoyPad* jp, int i, QWidget* parent )
: QWidget(parent) {
//initialize things, build the dialog
joypad = jp;
index = i;
/* This was in below, no idea what it does :( ...
* (joypad->axes+1)/2 +(joypad->buttons+1)/2 + 2
*/
LMain = new QGridLayout(this);
LMain->setSpacing(5);
LMain->setMargin(5);
flashcount = 0;
int insertCounter = 0;
quickset = NULL;
Axes = new AxisWidget*[joypad->axes];
for (int i = 0; i < joypad->axes; i++) {
Axes[i] = new AxisWidget(joypad->Axes[i],this);
connect( Axes[i], SIGNAL( flashed( bool ) ), this, SLOT( flash( bool )));
LMain->addWidget(Axes[i], insertCounter / 2, insertCounter %2);
insertCounter++;
}
Buttons = new ButtonWidget*[joypad->buttons];
for (int i = 0; i < joypad->buttons; i++) {
Buttons[i] = new ButtonWidget(joypad->Buttons[i],this);
connect( Buttons[i], SIGNAL( flashed( bool ) ), this, SLOT( flash( bool )));
LMain->addWidget(Buttons[i], insertCounter/2, insertCounter%2);
insertCounter++;
}
if(insertCounter % 2 == 1) {
insertCounter++;
}
insertCounter+=2;
BClear = new QPushButton("Clear", this);
connect(BClear, SIGNAL(clicked()), this, SLOT(clear()));
LMain->addWidget(BClear, insertCounter / 2, insertCounter %2);
insertCounter++;
BAll = new QPushButton("Quick Set", this);
LMain->addWidget(BAll, insertCounter /2, insertCounter%2);
connect(BAll, SIGNAL(clicked()), this, SLOT(setAll()));
}
JoyPadWidget::~JoyPadWidget() {
//so the joypad knows that we're done.
joypad->releaseWidget();
}
void JoyPadWidget::flash( bool on ) {
//true iff this entire widget was considered "flashed" before
bool wasOn = (flashcount != 0);
//adjust the count based on this new flash
flashcount += (on?1:-1);
//if we were on and should now be off, or visa versa, flash the whole widget
if (wasOn != (flashcount != 0))
emit flashed(index);
}
void JoyPadWidget::update() {
for (int i = 0; i < joypad->axes; i++) {
Axes[i]->update();
}
for (int i = 0; i < joypad->buttons; i++) {
Buttons[i]->update();
}
}
void JoyPadWidget::clear() {
joypad->toDefault();
update();
}
void JoyPadWidget::setAll() {
//quickset is NULL if there is no quickset dialog, and a pointer to the
//dialog otherwise. This is so we can forward jsevents properly.
quickset = new QuickSet(joypad);
quickset->exec();
update();
delete quickset;
quickset = NULL;
}
void JoyPadWidget::jsevent( js_event msg ) {
//notify the component this event applies to. this cannot generate anything
//other than a flash :)
if (msg.type == JS_EVENT_AXIS) {
Axes[msg.number]->jsevent(msg.value);
}
else {
Buttons[msg.number]->jsevent(msg.value);
}
//if we're doing quickset, it needs to know when we do something.
if (quickset != NULL)
quickset->jsevent(msg);
}

65
src/joypadw.h Normal file
View File

@ -0,0 +1,65 @@
#ifndef JOYPAD_WIDGET_H
#define JOYPAD_WIDGET_H
//parts for the widget
//Added by qt3to4:
#include <linux/joystick.h>
#include "axisw.h"
//this all relates to a JoyPad
#include "joypad.h"
//and a JoyPadWidget is composed of AxisWidgets and ButtonWidgets
#include "buttonw.h"
//JoyPadWidget also is what initiates the whole QuickSet procedure :)
#include "quickset.h"
//because of some circularity issues, I need to forward declare these.
class JoyPad;
class QuickSet;
//Widget for editing a JoyPad
class JoyPadWidget : public QWidget {
Q_OBJECT
public:
JoyPadWidget( JoyPad* jp, int i, QWidget* parent);
~JoyPadWidget();
//takes in an event and decides whether or not to flash anything
void jsevent( js_event msg );
public slots:
//called whenever one of the subwidgets flashes... used to determine
//when to emit the flashed() signal.
void flash( bool on );
//update all the components, that is, get the proper labels up on the buttons
void update();
//reset everything
void clear();
//quickset!
void setAll();
signals:
//happens whenever the tab that represents this joypadwidget should flash
//(either on or off) The int is the index of this widget so that this
//signal can be directly connected to FlashRadioArray's flash(int)
void flashed(int);
protected:
//the joypad this is linked to
JoyPad* joypad;
//the index of this widget IN THE WIDGET STACK! This is unique from
//joypad->index and has nothing to do with device number.
int index;
//how many times one of the components has flashed on minus how many
//times one of the components has flashed off. This is how we know when
//none of the components are left lit.
int flashcount;
//the parts of the dialog
QGridLayout *LMain;
AxisWidget **Axes;
ButtonWidget **Buttons;
QPushButton *BClear, *BAll;
//the quickset window, when we create it
QuickSet* quickset;
};
#endif

239
src/joyslider.cpp Normal file
View File

@ -0,0 +1,239 @@
#include "joyslider.h"
//Added by qt3to4:
JoySlider::JoySlider( int dz, int xz, int val, QWidget* parent )
:QWidget( parent )
{
//initialize :)
JoyVal = val;
DeadZone = dz;
XZone = xz;
setMinimumHeight(20);
}
void JoySlider::setValue( int newval )
{
//adjust the new position based on the throttle settings
if (throttle == 0) JoyVal = newval;
else if (throttle < 0) JoyVal = (newval + JOYMIN) / 2;
else JoyVal = (newval + JOYMAX) / 2;
//then redraw!
update();
}
void JoySlider::setThrottle( int newval )
{
//change throttle settings. This WILL quite likely cause minor issues with
//status if the axis is not currently at zero, but these will be corrected
//as soon as the axis moves again.
throttle = newval;
update();
}
int JoySlider::pointFor( int value, bool negative )
{
//complicated... this just finds the pixel the given value should be.
if (throttle == 0) {
int result = ((boxwidth - 4) * value) / JOYMAX;
if (negative) result = lboxstart + boxwidth - 2 - result;
else result += rboxstart + 2;
return result;
}
else {
int result = ((twidth - 4) * value) / JOYMAX;
if (negative) result = lboxstart + twidth - 2 - result;
else result += lboxstart + 2;
return result;
}
}
int JoySlider::valueFrom( int point )
{
//the inverse of above :)
if (throttle == 0) {
if (point <= lboxstart) return JOYMAX;
if (point >= lboxend - 2 && point <= rboxstart + 2) return 0;
if (point >= rboxend - 2) return JOYMAX;
if (point < lboxend - 2) return ((lboxend - point) * JOYMAX) / boxwidth;
if (point > rboxstart) return ((point - rboxstart) * JOYMAX) / boxwidth;
else return 0;
}
else if (throttle > 0) {
if (point <= lboxstart) return 0;
else if (point >= tend) return JOYMAX;
else return ((point - lboxstart) * JOYMAX) / twidth;
}
else {
if (point <= lboxstart - 2) return JOYMAX;
else if (point >= tend) return 0;
else return ((tend - point) * JOYMAX) / twidth;
}
}
void JoySlider::resizeEvent( QResizeEvent* )
{
//when we resize, we need to recalculate a bunch of measurements.
boxwidth = (this->width() - 6) / 2 - 1;
twidth = this->width() - 4;
boxheight = this->height() - 4;
lboxstart = 1;
lboxend = lboxstart + boxwidth - 1;
tend = lboxstart + twidth - 1;
rboxstart = lboxend + 5;
rboxend = rboxstart + boxwidth - 1;
}
void JoySlider::drawBox( int x, int width ) {
//draws a nice, pretty, 3d-styled box. that takes up the full height of the
//widget but is defined by x-coordinate and width
QPainter paint( this );
paint.setPen( (isEnabled())?Qt::white:palette().background().color() );
paint.setBrush( (isEnabled())?Qt::white:palette().background() );
paint.drawRect( x, 1, width, boxheight);
paint.setPen( palette().dark().color() );
paint.drawLine( x, 1 + boxheight, x, 1 );
paint.drawLine( x, 1, x + width - 1, 1);
paint.setPen( palette().shadow().color() );
paint.drawLine( x + 1, 1 + boxheight - 1, x + 1, 2);
paint.drawLine( x + 1, 2, x + width - 2, 2);
paint.setPen( palette().light().color() );
paint.drawLine( x + 2, 1 + boxheight - 1, x + width - 1, 1 + boxheight - 1);
paint.drawLine( x + width - 1, 1 + boxheight - 1, x + width - 1, 2);
paint.setPen( palette().midlight().color() );
paint.drawLine( x + 1, 1 + boxheight, x + width, 1 + boxheight );
paint.drawLine( x + width, 1 + boxheight, x + width, 1 );
}
void JoySlider::paintEvent( QPaintEvent* )
{
//when we need to redraw,
//start by making our boxes
if (throttle == 0) {
drawBox( lboxstart, boxwidth );
drawBox( rboxstart, boxwidth );
}
//or box, if we are in throttle mode.
else {
drawBox( lboxstart, twidth );
}
//if this is disabled, that's enough of that.
if (!isEnabled()) return;
//now we need to draw.
QPainter paint( this );
//prepare to draw a bar of the appropriate color
QColor bar;
if (abs(JoyVal) < DeadZone) bar = Qt::gray;
else if (abs(JoyVal) < XZone) bar = Qt::blue;
else bar = Qt::red;
paint.setPen( bar );
paint.setBrush( bar );
//find out the dimensions of the bar, then draw it
int width = (throttle == 0)?boxwidth:twidth;
int barlen = abs(((width - 4) * JoyVal) / JOYMAX);
if (JoyVal > 0)
paint.drawRect( ((throttle == 0)?rboxstart:lboxstart) + 2, 3, barlen, boxheight - 3 );
else if (JoyVal < 0)
paint.drawRect( lboxstart + width - 2 - barlen, 3, barlen, boxheight - 3 );
//and now draw the tabs! We only need one set if we're doing a throttle mode
//but we need two if we're not. However, it's important to draw the right
//set of tabs depending on the mode! Negative throttle gets negative tabs.
int point;
QPolygon shape;
paint.setPen( Qt::black );
paint.setBrush( Qt::blue );
if (throttle >= 0) {
point = pointFor(DeadZone, false);
shape.putPoints(0,5,
point, boxheight - 4,
point + 3, boxheight - 1,
point + 3, boxheight + 2,
point - 3, boxheight + 2,
point - 3, boxheight - 1);
paint.drawPolygon(shape);
}
if (throttle <= 0) {
point = pointFor(DeadZone, true);
shape.putPoints(0,5,
point, boxheight - 4,
point + 3, boxheight - 1,
point + 3, boxheight + 2,
point - 3, boxheight + 2,
point - 3, boxheight - 1);
paint.drawPolygon(shape);
}
paint.setBrush( Qt::red );
if (throttle >= 0) {
point = pointFor(XZone, false);
shape.putPoints(0,5,
point, boxheight - 4,
point + 3, boxheight - 1,
point + 3, boxheight + 2,
point - 3, boxheight + 2,
point - 3, boxheight - 1);
paint.drawPolygon(shape);
}
if (throttle <= 0) {
point = pointFor(XZone, true);
shape.putPoints(0,5,
point, boxheight - 4,
point + 3, boxheight - 1,
point + 3, boxheight + 2,
point - 3, boxheight + 2,
point - 3, boxheight - 1);
paint.drawPolygon(shape);
}
}
void JoySlider::mousePressEvent( QMouseEvent* e )
{
//store the x coordinate.
int xpt = e->x();
int result = 0;
//see if this happened near one of the tabs. If so, start dragging that tab.
if (throttle <= 0 && abs( xpt - pointFor( XZone, true )) < 5) result = DRAG_XZ;
else if (throttle <= 0 && abs( xpt - pointFor( DeadZone, true )) < 5) result = DRAG_DZ;
else if (throttle >= 0 && abs( xpt - pointFor( XZone, false )) < 5) result = DRAG_XZ;
else if (throttle >= 0 && abs( xpt - pointFor( DeadZone, false )) < 5) result = DRAG_DZ;
dragging = result;
};
void JoySlider::mouseReleaseEvent( QMouseEvent* )
{
//when the mouse releases, all dragging stops.
dragging = 0;
}
void JoySlider::mouseMoveEvent( QMouseEvent* e )
{
//get the x coordinate
int xpt = e->x();
//if we're dragging, move the appropriate tab!
if (dragging == DRAG_XZ)
{
XZone = valueFrom( xpt );
}
else if (dragging == DRAG_DZ)
{
DeadZone = valueFrom( xpt );
}
else return;
//if we moved a tab, redraw!
update();
}

76
src/joyslider.h Normal file
View File

@ -0,0 +1,76 @@
#ifndef Q_JOYSLIDER_H
#define Q_JOYSLIDER_H
//the parent of this
#include <stdlib.h>
#include <QResizeEvent>
#include <QPaintEvent>
#include <QMouseEvent>
#include <QPainter>
#include <QFrame>
#include <QHBoxLayout>
#include <QVBoxLayout>
#include <QComboBox>
#include <QSpinBox>
#include "constant.h"
//dragging constants.
//When dragging == DRAG_XZ, that means we are currently dragging the xZone mark
#define DRAG_XZ 1
//When dragging == DRAG_DZ, that means we are currently dragging the dZone mark
#define DRAG_DZ 2
class JoySlider : public QWidget
{
public:
JoySlider( int dz, int xz, int val, QWidget* parent );
//set where the axis physically is
void setValue( int );
//change the throttle mode
void setThrottle( int );
//get the current settings
int dZone() { return DeadZone; };
int xZone() { return XZone; };
protected:
//all for getting the widget to look right:
void drawBox( int x, int width );
void paintEvent( QPaintEvent* );
void resizeEvent( QResizeEvent* );
//for working with drag and drop:
void mousePressEvent( QMouseEvent* e );
void mouseReleaseEvent( QMouseEvent* );
void mouseMoveEvent( QMouseEvent* e );
private:
//dimensions of the box to draw!
int boxwidth;
int boxheight;
int rboxstart;
int rboxend;
int lboxstart;
int lboxend;
int twidth;
int tend;
//the throttle mode
int throttle;
//convert from joystick value to pixel position on the widget
//negative refers to whether or not we're on the "negative" end
//of the widget
int pointFor( int value, bool negative );
//convert from pixel position to joystick value
int valueFrom( int point );
//the current drag and drop state
int dragging;
//the axis' position
int JoyVal;
//the dead and extreme zone values
int DeadZone;
int XZone;
};
#endif

104
src/keycode.cpp Normal file
View File

@ -0,0 +1,104 @@
#include "keycode.h"
#include "getkey.h"
const QString ktos( int keycode )
{
if (keycode > MAXKEY || keycode < 0) keycode = 0;
if (keycode == 0) return "[NO KEY]";
QString xname = XKeysymToString(XKeycodeToKeysym(display, keycode,0));
//this section of code converts standard X11 keynames into much nicer names
//which are prettier, fit the dialogs better, and are more readily understandable.
//This is really ugly and I wish I didn't have to do this... that's why there
//is a config option to define PLAIN_KEYS and drop this whole section of code,
//instead using the default names for keys.
#ifndef PLAIN_KEYS
//the following code assumes xname is system independent and always
//in the same exact format.
QRegExp rx;
rx.setPattern("^\\w$");
//"a-z" -> "A-Z"
if (rx.exactMatch(xname)) return xname.toUpper();
rx.setPattern("(.*)_(.*)");
if (rx.exactMatch(xname)) {
QString first = rx.cap(1);
QString second = rx.cap(2);
rx.setPattern("^[RL]$");
//"Control_R" -> "R Control"
if (rx.exactMatch(second)) return second + " " + first;
rx.setPattern("^(Lock|Enter)$");
//"Caps_Lock" -> "Caps Lock"
//"KP_Enter" -> "KP Enter"
if (rx.exactMatch(second)) return first + " " + second;
//the following assumes all number pads are laid out alike.
if (xname == "KP_Home") return "KP 7";
if (xname == "KP_Up") return "KP 8";
if (xname == "KP_Prior") return "KP 9";
if (xname == "KP_Subtract") return "KP -";
if (xname == "KP_Left") return "KP 4";
if (xname == "KP_Begin") return "KP 5";
if (xname == "KP_Right") return "KP 6";
if (xname == "KP_Add") return "KP +";
if (xname == "KP_End") return "KP 1";
if (xname == "KP_Down") return "KP 2";
if (xname == "KP_Next") return "KP 3";
if (xname == "KP_Insert") return "KP 0";
if (xname == "KP_Delete") return "KP .";
if (xname == "KP_Multiply") return "KP *";
if (xname == "KP_Divide") return "KP /";
return xname;
}
if (xname == "minus") return "-";
if (xname == "equal") return "=";
if (xname == "bracketleft") return "[";
if (xname == "bracketright") return "]";
if (xname == "semicolon") return ";";
if (xname == "apostrophe") return "'";
if (xname == "grave") return "`";
if (xname == "backslash") return "\\";
if (xname == "comma") return ",";
if (xname == "period") return ".";
if (xname == "slash") return "/";
if (xname == "space") return "Space";
if (xname == "Prior") return "PageUp";
if (xname == "Next") return "PageDown";
#endif
//if none of that succeeded,
return xname;
}
KeyButton::KeyButton( QString name, int val, QWidget* parent, bool m, bool nowMouse)
:QPushButton(nowMouse?"Mouse " + QString::number(val):QString(ktos(val)), parent) {
mouse = m;
mouseClicked = nowMouse;
buttonname = name;
value = val;
connect( this, SIGNAL( clicked() ), SLOT( onClick() ));
}
void KeyButton::onClick() {
//when clicked, ask for a key!
value = GetKey( buttonname, mouse ).exec();
//if the return value was a mouse click...
if (value > MOUSE_OFFSET) {
mouseClicked = true;
value -= MOUSE_OFFSET;
setText( "Mouse " + QString::number(value));
}
//otherwise, it was a key press!
else {
mouseClicked = false;
setText( ktos(value));
}
}

36
src/keycode.h Normal file
View File

@ -0,0 +1,36 @@
#ifndef KEYCODE_H
#define KEYCODE_H
//To create the "press a key" dialog:
#include <QPushButton>
#include <QDialog>
#include <QPaintEvent>
#include <QPainter>
#include "constant.h"
//Produce a string for any keycode
const QString ktos( int keycode );
//The X11 display, taken from main.cpp
extern Display* display;
//a button that requests a keycode from the user when clicked.
class KeyButton : public QPushButton {
Q_OBJECT
public:
KeyButton(QString name, int val, QWidget* parent, bool m = false, bool nowMouse = false);
int getValue() {return value;};
int choseMouse() {return mouseClicked;};
protected slots:
void onClick();
private:
QString buttonname;
int value;
bool mouse;
bool mouseClicked;
};
#endif

390
src/layout.cpp Normal file
View File

@ -0,0 +1,390 @@
#include "layout.h"
#include <errno.h>
//initialize things and set up an icon :)
LayoutManager::LayoutManager( bool useTrayIcon ) {
//no LayoutEdit yet.
le = NULL;
//prepare the popup first.
Popup = new QMenu();
fillPopup();
connect(Popup,SIGNAL(triggered(QAction*)),this, SLOT(trayMenu(QAction*)));
//make a tray icon
if (useTrayIcon) {
TrayIcon* Tray = new TrayIcon(QPixmap(ICON24),NAME,Popup,0,"tray");
connect(Tray, SIGNAL( clicked(const QPoint&, int)), this, SLOT( trayClick()));
Tray->show();
}
//or make a floating icon
else {
FloatingIcon* Icon = new FloatingIcon(QPixmap(ICON64),Popup,0,"tray");
connect(Icon, SIGNAL( clicked()), this, SLOT( trayClick()));
connect(Icon, SIGNAL( closed()), qApp, SLOT( quit()));
Icon->show();
}
//no layout loaded at start.
setLayoutName(NL);
}
QString LayoutManager::getFileName( QString layoutname ) {
return settingsDir + layoutname + ".lyt";
}
bool LayoutManager::load(const QString& name) {
//it's VERY easy to load NL :)
if (name == NL) {
clear();
return true;
}
QFile file(getFileName(name));
//if the file isn't available,
if (!file.exists()) {
error("Load error","Failed to find a layout named " + name);
return false;
}
//if the file isn't readable,
if (!file.open(QIODevice::ReadOnly)) {
error("Load error","Error reading from file " + file.fileName());
return false;
}
//reset all the joypads.
//note that we don't use available here, but joypads instead. This is so
//if one layout has more joypads than this one does, this won't have the
//extra settings left over after things are supposed to be "cleared"
QHashIterator<int, JoyPad*> it( joypads );
while (it.hasNext())
{
it.next();
it.value()->toDefault();
}
//start reading joypads!
QTextStream stream( &file );
QString input = stream.readLine().toLower();
QRegExp quoted("\"(.*)\"");
bool okay;
int num;
while (input != QString::null) {
QStringList words = input.split(" ");
//if this line is specifying a joystick
if (words[0] == "joystick") {
num = words[1].toInt(&okay);
//make sure the number of the joystick is valid
if (!okay || okay < 1) {
error( "Load error", "Error reading joystick definition. Expected: Joysyick 1 {");
if (name != CurrentLayout) reload();
else clear();
return false;
}
//if there was no joypad defined for this index before, make it now!
if (joypads[num-1] == 0) {
joypads.insert(num-1, new JoyPad(num-1, 0));
}
//try to read the joypad, report error on fail.
if (!joypads[num-1]->readConfig(&stream)) {
error( "Load error", "Error reading definition for joystick " + QString::number(num-1));
//if this was attempting to change to a new layout and it failed,
//revert back to the old layout.
if (name != CurrentLayout) reload();
//to keep from going into an infinite loop, if there is no good
//layout to fall back on, go to NL.
else clear();
return false;
}
}
//read a new line.
input = stream.readLine().toLower();
}
//if loading succeeded, this is our new layout.
setLayoutName(name);
return true;
}
bool LayoutManager::load() {
//try to load the file named "layout" to retrieve the last used layout name
QFile file( settingsDir + "layout");
QString name;
if (file.open(QIODevice::ReadOnly)) {
QTextStream stream(&file);
name = stream.readLine();
file.close();
//if there was no name, don't load.
if (name == "") {
return false;
}
//if there was a name, try to load it! Note, this will still return
//false if the name is invalid ( see load() )
return load(name);
}
//if the file isn't available to open, don't load.
return false;
}
bool LayoutManager::reload() {
return load(CurrentLayout);
}
void LayoutManager::clear() {
//reset all the joypads...
QHashIterator<int, JoyPad*> it (joypads);
while (it.hasNext())
{
it.next();
it.value()->toDefault();
}
//and call our layout NL
setLayoutName(NL);
}
void LayoutManager::save() {
if (CurrentLayout == NL) {
saveAs();
return;
}
//get a filename
QString filename = getFileName( CurrentLayout );
QFile file(filename);
//if it's good, start writing the file
if (file.open(QIODevice::WriteOnly)) {
QTextStream stream( &file );
stream << "# "NAME" Layout File\n\n";
QHashIterator<int, JoyPad*> it (joypads);
while (it.hasNext())
{
it.next();
it.value()->write( &stream );
}
file.close();
}
//if it's not, error.
else
error("Save error", "Could not open file " + filename + ", layout not saved.");
}
void LayoutManager::saveAs() {
bool ok;
//request a new name!
QString name = QInputDialog::getText(0, NAME" - Name new layout","Enter a name for the new layout:", QLineEdit::Normal, QString::null, &ok );
if (!ok) {
return;
}
QFile file(settingsDir + name + ".lyt");
//don't overwrite an existing layout.
if (file.exists()) {
error("Save error", "That name's already taken!");
return;
}
//now that the new layout has a name, that is the name we should use.
setLayoutName(name);
//since we have a new name for this layout now, we can save it normally :)
save();
//add the new name to our lists
fillPopup();
if (le != NULL) {
le->updateLayoutList();
}
printf("returning, user provided input\n");
}
void LayoutManager::saveDefault() {
QFile file( settingsDir + "layout");
if (file.open(QIODevice::WriteOnly)) {
QTextStream stream(&file);
stream << CurrentLayout;
file.close();
}
}
void LayoutManager::remove() {
if (CurrentLayout == NL) return;
if (QMessageBox::warning( 0, NAME" - Delete layout?","Remove layout permanently from your hard drive?", "Yes", "No", 0, 0, 1 ) == 1) return;
QString filename = getFileName( CurrentLayout );
if (!QFile(filename).remove()) {
error("Remove error", "Could not remove file " + filename);
}
fillPopup();
if (le != NULL) {
le->updateLayoutList();
}
clear();
}
QStringList LayoutManager::getLayoutNames() {
//goes through the list of .lyt files and removes the file extensions ;)
QStringList result = QDir(settingsDir).entryList(QStringList("*.lyt"));
for ( QStringList::Iterator it = result.begin(); it != result.end(); ++it ) {
*it = (*it).left((*it).length() - 4);
}
//and, of course, there's always NL.
result.prepend(NL);
return result;
}
void LayoutManager::setLayoutName(QString name) {
CurrentLayout = name;
fillPopup();
if (le != NULL) {
le->setLayout(name);
}
}
void LayoutManager::trayClick() {
//don't show the dialog if there aren't any joystick devices plugged in
if (available.count() == 0) {
error("No joystick devices available","No joystick devices are currently available to configure.\nPlease plug in a gaming device and select\n\"Update Joystick Devices\" from the popup menu.");
return;
}
//otherwise, make a new LayoutEdit dialog and show it.
le = new LayoutEdit(this);
le->setLayout(CurrentLayout);
//note, this will cause the menu to hang. You cannot use the menu while the
//dialog is active. I'd rather it not work out that way, but this makes my
//code MUCH simpler for a small inconvenience that shouldn't matter. For
//instance, I don't have to worry about the current joysticks changing
//while there's a dialog and therefore adjusting the dialog to match.
le->exec();
delete le;
le = NULL;
}
void LayoutManager::trayMenu(QAction *menuItemAction) {
//if they clicked on a Layout name, load it!
//note that the other options are handled with their own special functions
printf("%s\n", qPrintable(menuItemAction->text()));
printf("oh hi\n");
//printf("%d\n", Popup->
if (Popup->actions().indexOf(menuItemAction) > 1 && menuItemAction->text() != "Quit" &&
menuItemAction->text() != "Update lyaout list" &&
menuItemAction->text() != "Update joystick devices") {
load(menuItemAction->text());
}
}
void LayoutManager::fillPopup() {
printf("starting fillPopup\n");
//start with an empty slate
Popup->clear();
//make a list of joystick devices
QString devs = "Joysticks: ";
QHashIterator<int, JoyPad*> it( available );
while (it.hasNext())
{
it.next();
devs += QString::number(it.key() + 1) + " ";
}
QAction *temp = Popup->addAction(devs);
Popup->addSeparator(/*temp*/);
//add in the Update options
QAction *tempAdd = new QAction("Update layout list", this);
connect(tempAdd, SIGNAL(triggered(bool)), this, SLOT(fillPopup()));
Popup->addAction(tempAdd);
tempAdd = new QAction("Update joystick devices", this);
connect(tempAdd, SIGNAL(triggered(bool)), this, SLOT(updateJoyDevs()));
Popup->addAction(tempAdd);
Popup->addSeparator(/*temp*/);
//then add all the layout names
QStringList names = getLayoutNames();
for ( QStringList::Iterator it = names.begin(); it != names.end(); ++it ) {
temp = Popup->addAction(*it);
temp->setCheckable(true);
//put a check by the current one ;)
if (CurrentLayout == (*it)) {
temp->setChecked(true);
}
}
Popup->addSeparator();
//and, at the end, quit!
Popup->addAction("Quit",qApp,SLOT(quit()));
printf("returning from fill popup\n");
}
void LayoutManager::updateJoyDevs() {
printf("entering update JoyDevs\n");
QString devdir = DEVDIR;
//reset all joydevs to sentinal value (-1)
do {
QHashIterator<int, JoyPad*> it( joypads );
while (it.hasNext() ) {
it.next();
it.value()->unsetDev();
}
} while (0);
//clear out the list of previously available joysticks
available.clear();
//set all joydevs anew (create new JoyPad's if necesary)
QDir DeviceDir(devdir);
QStringList devices = DeviceDir.entryList(QStringList("js*"), QDir::System );
QRegExp devicename(".*\\js(\\d+)");
int joydev;
int index;
//for every joystick device in the directory listing...
//(note, with devfs, only available devices are listed)
for (QStringList::Iterator it = devices.begin(); it != devices.end(); ++it) {
//try opening the device.
printf("%s\n", qPrintable(devdir + "/" + (*it)));
joydev = open( qPrintable(devdir + "/" + (*it)), O_RDONLY | O_NONBLOCK);
//if it worked, then we have a live joystick! Make sure it's properly
//setup.
if (joydev > 0) {
printf("joystick found, constructing...\n");
devicename.indexIn(*it);
index = QString(devicename.cap(1)).toInt();
JoyPad* joypad;
//if we've never seen this device before, make a new one!
if (joypads[index] == 0) {
struct pollfd read_struct;
read_struct.fd = joydev;
read_struct.events = POLLIN;
char buf[10];
while(poll(&read_struct, 1, 2)!=0) {
printf("reading junk data\n");
read(joydev, buf, 10);
}
joypad = new JoyPad( index, joydev );
joypads.insert(index,joypad);
}
else {
printf("resetting to dev...\n");
joypad = joypads[index];
joypad->resetToDev(joydev);
}
//make this joystick device available.
available.insert(index,joypad);
}
else {
int errsv = errno;
printf("well fuck!\n");
printf("%s\n", strerror(errsv));
}
}
printf("done rebuilding joystick devices\n");
//when it's all done, rebuild the popup menu so it displays the correct
//information.
fillPopup();
//the actual update process is handled by main.cpp, we just need to signal
//ourselves to do it.
//raise(SIGUSR1);
printf("returning from rebuild function\n");
}

88
src/layout.h Normal file
View File

@ -0,0 +1,88 @@
#ifndef JOY_LAYOUT_H
#define JOY_LAYOUT_H
//to allow for interprocess communications (ie, signaling a running instance of
//qjoypad by running "qjoypad layout-name", etc.) QJoyPad uses signals to
//triger certain events. This is for signaling the main program to update
//the joystick device list.
#include <signal.h>
#include <QAction>
#include <QDir>
#include <QMenu>
#include <QApplication>
#include <QDialog>
#include <QInputDialog>
#include <poll.h>
//a layout handles several joypads
#include "joypad.h"
//for errors
#include "error.h"
//so we know which joypads have RL equivalents
#include "device.h"
//to display the tray icon
#include "trayicon/trayicon.h"
//For displaying a floating icon instead of a tray icon
#include "icon.h"
//So we can know if there is a graphical version of the Layout Manager displayed
#include "layout_edit.h"
//for recognizing when the special empty layout is in use
#define NL "[NO LAYOUT]"
//where QJoyPad saves its settings!
const QString settingsDir(QDir::homePath() + "/.qjoypad3/");
//handles loading, saving, and changing of layouts
class LayoutManager : public QObject {
friend class LayoutEdit;
Q_OBJECT
public:
LayoutManager( bool useTrayIcon);
//produces a list of the names of all the available layout.
QStringList getLayoutNames();
public slots:
//load a layout with a given name
bool load(const QString& name);
//look for the last loaded layout and try to load that.
bool load();
//load the current layout, overwriting any changes made to it.
bool reload();
//reset to a blank, empty layout
void clear();
//save the current layout with its current name
void save();
//save the current layout with a new name
void saveAs();
//save the currently loaded layout so it can be recalled later
void saveDefault();
//get rid of a layout
void remove();
//when the tray icon is clicked
void trayClick();
//when the user selects an item on the tray's popup menu
void trayMenu(QAction* menuItemAction);
//rebuild the popup menu with the current information
void fillPopup();
//update the list of available joystick devices
void updateJoyDevs();
private:
//change to the given layout name and make all the necesary adjustments
void setLayoutName(QString name);
//get the file name for a layout name
QString getFileName( QString layoutname );
//the layout that is currently in use
QString CurrentLayout;
//the popup menu from the tray/floating icon
QMenu* Popup;
//if there is a LayoutEdit open, this points to it. Otherwise, NULL.
LayoutEdit* le;
};
#endif

132
src/layout_edit.cpp Normal file
View File

@ -0,0 +1,132 @@
#include "layout_edit.h"
//build the dialog
LayoutEdit::LayoutEdit( LayoutManager* l ) {
lm = l;
setWindowTitle( NAME );
setWindowIcon(QPixmap(ICON24));
LMain = new QVBoxLayout( this);
LMain->setSpacing(5);
LMain->setMargin(5);
QFrame* frame = new QFrame(this);
frame->setFrameStyle(QFrame::Box | QFrame::Sunken );
QGridLayout* g = new QGridLayout(frame);
g->setMargin(5);
g->setSpacing(5);
CLayouts = new QComboBox(frame);
connect( CLayouts, SIGNAL(activated( const QString& )), lm, SLOT(load(const QString&)));
g->addWidget(CLayouts,0,0,1,4);
//most of these buttons can link directly into slots in the LayoutManager
BAdd = new QPushButton("Add", frame);
connect(BAdd, SIGNAL(clicked()), lm, SLOT(saveAs()));
g->addWidget(BAdd,1,0);
BRem = new QPushButton("Remove", frame);
connect(BRem, SIGNAL(clicked()), lm, SLOT(remove()));
g->addWidget(BRem,1,1);
BUpd = new QPushButton("Update", frame);
connect(BUpd, SIGNAL(clicked()), lm, SLOT(save()));
g->addWidget(BUpd,1,2);
BRev = new QPushButton("Revert", frame);
connect(BRev, SIGNAL(clicked()), lm, SLOT(reload()));
g->addWidget(BRev,1,3);
LMain->addWidget( frame );
//produce a list of names for the FlashRadioArray
//this is only necesary since joystick devices need not always be
//contiguous
int padcount = available.count();
QString names[padcount];
int i = 0;
do
{
QHashIterator<int, JoyPad*> it( available );
while (it.hasNext())
{
it.next();
names[i] = it.value()->getName();
++i;
}
} while (0);
//flash radio array
JoyButtons = new FlashRadioArray(padcount, names, true, this );
LMain->addWidget( JoyButtons );
//we have a WidgetStack to represent the multiple joypads
PadStack = new QStackedWidget( this );
PadStack->setFrameStyle(QFrame::Box | QFrame::Sunken );
LMain->addWidget(PadStack);
//go through each of the available joysticks
i = 0; // i is the current index into PadStack
do
{
QHashIterator<int, JoyPad*> it(available);
while (it.hasNext())
{
it.next();
//add a new JoyPadWidget to the stack
PadStack->insertWidget( i,it.value()->widget(PadStack,i) );
//every time it "flashes", flash the associated tab.
connect( PadStack->widget(i), SIGNAL( flashed( int ) ), JoyButtons, SLOT( flash( int )));
++i;
}
} while (0);
//whenever a new tab is selected, raise the appropriate JoyPadWidget
connect( JoyButtons, SIGNAL( changed( int ) ), PadStack, SLOT( setCurrentIndex( int )));
updateLayoutList();
//add the buttons at the bottom.
QHBoxLayout* h = new QHBoxLayout(0);
h->setMargin(0);
h->setSpacing(5);
QPushButton* close = new QPushButton( "-- Close Dialog --", this );
connect(close, SIGNAL(clicked()), this, SLOT(close()));
h->addWidget(close);
QPushButton* quit = new QPushButton( "-- Quit --", this );
connect( quit, SIGNAL( clicked() ), qApp, SLOT(quit()));
h->addWidget(quit);
LMain->addLayout(h);
blockEvents = false;
}
void LayoutEdit::setLayout(QString layout) {
//change the text,
CLayouts->setItemText(CLayouts->currentIndex(), layout);
//update all the JoyPadWidgets.
for (uint i = 0; i < available.count(); i++) {
((JoyPadWidget*)PadStack->widget(i))->update();
}
}
void LayoutEdit::updateLayoutList() {
//blank the list, then load in new names from the LayoutManager.
CLayouts->clear();
QStringList layouts = lm->getLayoutNames();
//For some reason, insertStringList doesn't want to work for me!
for ( QStringList::Iterator it = layouts.begin(); it != layouts.end(); ++it ) {
CLayouts->insertItem(-1,*it);
}
CLayouts->setItemText(CLayouts->currentIndex(), lm->CurrentLayout);
}
void LayoutEdit::windowActivationChange( bool oldActive ) {
if (oldActive) return;
//whenever the window becomes active, release all pressed buttons! This way
//you don't get any presses without releases to confuse things.
blockEvents = true;
QHashIterator<int, JoyPad*> it( available );
while (it.hasNext())
{
printf("iterating and releasing\n");
it.next();
it.value()->release();
}
printf("done releasing!\n");
blockEvents = false;
}

40
src/layout_edit.h Normal file
View File

@ -0,0 +1,40 @@
#ifndef LAYOUT_EDIT_H
#define LAYOUT_EDIT_H
#include <QStackedWidget>
//for the tab list of joypads
#include "flash.h"
//this is a front end for the non-GUI LayoutManager
class LayoutEdit;
#include "layout.h"
//so we can see the available devices
#include "device.h"
//so we can use the LayoutEditer to edit key layouts :)
#include "joypadw.h"
class LayoutManager;
class LayoutEdit : public QDialog {
public:
LayoutEdit( LayoutManager* l );
//swap to a new layout
void setLayout(QString layout);
//update the list of available layouts
void updateLayoutList();
protected:
//the layout manager this represents
LayoutManager* lm;
//find out when the window is activated.
virtual void windowActivationChange( bool oldActive );
bool blockEvents;
//parts of the dialog:
QVBoxLayout *LMain;
QStackedWidget *PadStack;
FlashRadioArray *JoyButtons;
QComboBox* CLayouts;
QPushButton *BAdd, *BRem, *BUpd, *BRev;
};
#endif

275
src/main.cpp Normal file
View File

@ -0,0 +1,275 @@
#define MAIN
//to create a qapplication
#include <QFile>
//for ouput when there is no GUI going
#include <stdio.h>
//to create and handle signals for various events
#include <signal.h>
//to load layouts
#include "layout.h"
//to give event.h the current X11 display
#include "event.h"
//to update the joystick device list
#include "device.h"
//to produce errors!
#include "error.h"
#include <QX11Info>
#include <poll.h>
#include <cstdlib>
//for making universally available variables
extern Display* display; //from event.h
QHash<int, JoyPad*> available; //to device.h
QHash<int, JoyPad*> joypads; //to device.h
//variables needed in various functions in this file
LayoutManager* lm;
QString devdir = DEVDIR;
//update the joystick devices!
void buildJoyDevices() {
//reset all joydevs to sentinal value (-1)
do {
QHashIterator<int, JoyPad*> it( joypads );
while (it.hasNext() ) {
it.next();
it.value()->unsetDev();
}
} while (0);
//clear out the list of previously available joysticks
available.clear();
//set all joydevs anew (create new JoyPad's if necesary)
QDir DeviceDir(devdir);
QStringList devices = DeviceDir.entryList(QStringList("js*"), QDir::System );
QRegExp devicename(".*\\js(\\d+)");
int joydev;
int index;
//for every joystick device in the directory listing...
//(note, with devfs, only available devices are listed)
for (QStringList::Iterator it = devices.begin(); it != devices.end(); ++it) {
//try opening the device.
joydev = open( (devdir + "/" + (*it)).toStdString().c_str(), O_RDONLY | O_NONBLOCK);
//if it worked, then we have a live joystick! Make sure it's properly
//setup.
if (joydev > 0) {
devicename.indexIn(*it);
index = QString(devicename.cap(1)).toInt();
JoyPad* joypad;
//if we've never seen this device before, make a new one!
if (joypads[index] == 0) {
struct pollfd read_struct;
read_struct.fd = joydev;
read_struct.events = POLLIN;
char buf[10];
while(poll(&read_struct, 1, 2)!=0) {
printf("reading junk data\n");
read(joydev, buf, 10);
}
joypad = new JoyPad( index, joydev );
joypads.insert(index,joypad);
}
else {
joypad = joypads[index];
joypad->resetToDev(joydev);
}
//make this joystick device available.
available.insert(index,joypad);
}
}
printf("done rebuilding joystick devices\n");
//when it's all done, rebuild the popup menu so it displays the correct
//information.
lm->fillPopup();
}
//signal handler for SIGIO
//SIGIO means that a new layout should be loaded. It is saved in
// ~/.qjoypad/layout, where the last used layout is put.
void catchSIGIO( int sig )
{
lm->load();
//remember to catch this signal again next time.
signal( sig, catchSIGIO );
}
//signal handler for SIGUSR1
//SIGUSR1 means that we should update the available joystick device list.
void catchSIGUSR1( int sig ) {
//buildJoyDevices();
lm->updateJoyDevs();
//remember to catch this signal again next time.
signal( sig, catchSIGUSR1 );
}
/* A new feature to add? We'll see.
void catchSIGUSR2( int sig ) {
lm->trayClick();
signal( sig, catchSIGUSR2 );
}
*/
int main( int argc, char **argv )
{
//create a new event loop. This will be captured by the QApplication
//when it gets created
QApplication a( argc, argv );
//where to look for settings. If it does not exist, it will be created
QDir dir(settingsDir);
//if there is no new directory and we can't make it, complain
if (!dir.exists() && !dir.mkdir(settingsDir)) {
printf("Couldn't create the QJoyPad save directory (%s)!", settingsDir.toStdString().c_str());
return 1;
}
//start out with no special layout.
QString layout = "";
//by default, we use a tray icon
bool useTrayIcon = true;
//this execution wasn't made to update the joystick device list.
bool update = false;
//parse command-line options
for (int i = 1; i < a.argc(); i++) {
//if a device directory was specified,
if (QRegExp("-{1,2}device").exactMatch(a.argv()[i])) {
++i;
if (i < a.argc()) {
if (QFile::exists(a.argv()[i])) {
devdir = a.argv()[i];
}
else {
error("Command Line Argument Problems", "No such directory: " + QString(a.argv()[i]));
continue;
}
}
}
//if no-tray mode was requested,
else if (QRegExp("-{1,2}notray").exactMatch(a.argv()[i])) {
useTrayIcon = false;
}
//if this execution is just meant to update the joystick devices,
else if (QRegExp("-{1,2}update").exactMatch(a.argv()[i])) {
update = true;
}
//if help was requested,
else if (QRegExp("-{1,2}h(elp)?").exactMatch(a.argv()[i])) {
printf(NAME"\nUsage: qjoypad [--device \"/device/path\"] [--notray] [\"layout name\"]\n\nOptions:\n --device path Look for joystick devices in \"path\". This should\n be something like \"/dev/input\" if your game\n devices are in /dev/input/js0, /dev/input/js1, etc.\n --notray Do not use a system tray icon. This is useful for\n window managers that don't support this feature.\n --update Force a running instance of QJoyPad to update its\n list of devices and layouts.\n \"layout name\" Load the given layout in an already running\n instance of QJoyPad, or start QJoyPad using the\n given layout.\n");
return 1;
}
//in all other cases, an argument is assumed to be a layout name.
//note: only the last layout name given will be used.
else layout = a.argv()[i];
}
//if the user specified a layout to use,
if (layout != "")
{
//then we try to store that layout in the last-used layout spot, to be
//loaded by default.
QFile file( settingsDir + "layout");
if (file.open(QIODevice::WriteOnly))
{
QTextStream stream( &file );
stream << layout;
file.close();
}
}
//create a pid lock file.
QFile pidFile( "/tmp/qjoypad.pid" );
//if that file already exists, then qjoypad is already running!
if (pidFile.exists())
{
int pid;
if (pidFile.open( QIODevice::ReadOnly ));
{
//try to get that pid...
QTextStream( &pidFile ) >> pid;
pidFile.close();
//if we can signal the pid (ie, if the process is active)
if (kill(pid,0) == 0)
{
//then prevent two instances from running at once.
//however, if we are setting the layout or updating the device
//list, this is not an error and we shouldn't make one!
if (layout == "" && update == false) error("Instance Error","There is already a running instance of QJoyPad; please close\nthe old instance before starting a new one.");
else {
//if one of these is the case, send the approrpriate signal!
if (update == true)
kill(pid,SIGUSR1);
if (layout != "")
kill(pid,SIGIO);
}
//and quit. We don't need two instances.
return 0;
}
}
}
//now we can try to create and write our pid to the lock file.
if (pidFile.open( QIODevice::WriteOnly ))
{
QTextStream( &pidFile ) << getpid();
pidFile.close();
}
//prepare the signal handlers
signal( SIGIO, catchSIGIO );
signal( SIGUSR1, catchSIGUSR1 );
// signal( SIGUSR2, catchSIGUSR2 );
//capture the current display for event.h
display = QX11Info::display();
//create a new LayoutManager with a tray icon / floating icon, depending
//on the user's request
lm = new LayoutManager(useTrayIcon);
//build the joystick device list for the first time,
//buildJoyDevices();
lm->updateJoyDevs();
//load the last used layout (Or the one given as a command-line argument)
lm->load();
//and run the program!
int result = a.exec();
//when everything is done, save the current layout for next time...
lm->saveDefault();
//remove the lock file...
pidFile.remove();
//and terminate!
return result;
}

184
src/portinglog.txt Normal file
View File

@ -0,0 +1,184 @@
Log for qt3to4 on Fri Dec 26 18:59:56 2008. Number of log entries: 101
In file /home/john/qjoypad-3.4.1/src/axis.cpp at line 21 column 28: QTextStream -> Q3TextStream
In file /home/john/qjoypad-3.4.1/src/axis.cpp at line 115 column 29: QTextStream -> Q3TextStream
In file /home/john/qjoypad-3.4.1/src/axis.cpp: Added the following include directives:
#include <Q3TextStream>
In file /home/john/qjoypad-3.4.1/src/axis_edit.cpp at line 22 column 12: QVBoxLayout -> Q3VBoxLayout
In file /home/john/qjoypad-3.4.1/src/axis_edit.cpp at line 22 column 33: QVBoxLayout -> Q3VBoxLayout
In file /home/john/qjoypad-3.4.1/src/axis_edit.cpp at line 24 column 12: QHBoxLayout -> Q3HBoxLayout
In file /home/john/qjoypad-3.4.1/src/axis_edit.cpp at line 24 column 33: QHBoxLayout -> Q3HBoxLayout
In file /home/john/qjoypad-3.4.1/src/axis_edit.cpp at line 25 column 13: QVBoxLayout -> Q3VBoxLayout
In file /home/john/qjoypad-3.4.1/src/axis_edit.cpp at line 25 column 35: QVBoxLayout -> Q3VBoxLayout
In file /home/john/qjoypad-3.4.1/src/axis_edit.cpp at line 41 column 23: QFrame -> Q3Frame
In file /home/john/qjoypad-3.4.1/src/axis_edit.cpp at line 42 column 33: QFrame -> Q3Frame
In file /home/john/qjoypad-3.4.1/src/axis_edit.cpp at line 42 column 47: QFrame -> Q3Frame
In file /home/john/qjoypad-3.4.1/src/axis_edit.cpp at line 43 column 22: QVBoxLayout -> Q3VBoxLayout
In file /home/john/qjoypad-3.4.1/src/axis_edit.cpp at line 54 column 20: QFrame -> Q3Frame
In file /home/john/qjoypad-3.4.1/src/axis_edit.cpp at line 55 column 30: QFrame -> Q3Frame
In file /home/john/qjoypad-3.4.1/src/axis_edit.cpp at line 55 column 44: QFrame -> Q3Frame
In file /home/john/qjoypad-3.4.1/src/axis_edit.cpp at line 56 column 20: QHBoxLayout -> Q3HBoxLayout
In file /home/john/qjoypad-3.4.1/src/axis_edit.cpp at line 70 column 20: QHBoxLayout -> Q3HBoxLayout
In file /home/john/qjoypad-3.4.1/src/axis_edit.cpp: Added the following include directives:
#include <QPixmap> #include <Q3HBoxLayout> #include <Q3VBoxLayout> #include <QLabel> #include <Q3Frame>
In file /home/john/qjoypad-3.4.1/src/axisw.cpp: Added the following include directives:
#include <QMouseEvent>
In file /home/john/qjoypad-3.4.1/src/button.cpp at line 18 column 30: QTextStream -> Q3TextStream
In file /home/john/qjoypad-3.4.1/src/button.cpp at line 64 column 31: QTextStream -> Q3TextStream
In file /home/john/qjoypad-3.4.1/src/button.cpp: Added the following include directives:
#include <Q3TextStream>
In file /home/john/qjoypad-3.4.1/src/button_edit.cpp at line 14 column 12: QVBoxLayout -> Q3VBoxLayout
In file /home/john/qjoypad-3.4.1/src/button_edit.cpp at line 14 column 33: QVBoxLayout -> Q3VBoxLayout
In file /home/john/qjoypad-3.4.1/src/button_edit.cpp at line 19 column 12: QHBoxLayout -> Q3HBoxLayout
In file /home/john/qjoypad-3.4.1/src/button_edit.cpp at line 19 column 33: QHBoxLayout -> Q3HBoxLayout
In file /home/john/qjoypad-3.4.1/src/button_edit.cpp at line 28 column 20: QHBoxLayout -> Q3HBoxLayout
In file /home/john/qjoypad-3.4.1/src/button_edit.cpp: Added the following include directives:
#include <Q3VBoxLayout> #include <QPixmap> #include <Q3HBoxLayout>
In file /home/john/qjoypad-3.4.1/src/buttonw.cpp: Added the following include directives:
#include <QMouseEvent>
No changes made to file /home/john/qjoypad-3.4.1/src/event.cpp
In file /home/john/qjoypad-3.4.1/src/flash.cpp at line 56 column 25: QHBoxLayout -> Q3HBoxLayout
In file /home/john/qjoypad-3.4.1/src/flash.cpp at line 58 column 25: QVBoxLayout -> Q3VBoxLayout
In file /home/john/qjoypad-3.4.1/src/flash.cpp: Added the following include directives:
#include <Q3VBoxLayout> #include <Q3HBoxLayout>
In file /home/john/qjoypad-3.4.1/src/icon.cpp at line 7 column 20: qpopupmenu.h -> q3popupmenu.h
In file /home/john/qjoypad-3.4.1/src/icon.cpp at line 9 column 59: QPopupMenu -> Q3PopupMenu
In file /home/john/qjoypad-3.4.1/src/icon.cpp: Added the following include directives:
#include <QPixmap> #include <QCloseEvent> #include <QMouseEvent>
In file /home/john/qjoypad-3.4.1/src/joypad.cpp at line 42 column 26: QIntDictIterator -> Q3IntDictIterator
In file /home/john/qjoypad-3.4.1/src/joypad.cpp at line 44 column 26: QIntDictIterator -> Q3IntDictIterator
In file /home/john/qjoypad-3.4.1/src/joypad.cpp at line 50 column 26: QIntDictIterator -> Q3IntDictIterator
In file /home/john/qjoypad-3.4.1/src/joypad.cpp at line 52 column 26: QIntDictIterator -> Q3IntDictIterator
In file /home/john/qjoypad-3.4.1/src/joypad.cpp at line 57 column 30: QTextStream -> Q3TextStream
In file /home/john/qjoypad-3.4.1/src/joypad.cpp at line 114 column 31: QTextStream -> Q3TextStream
In file /home/john/qjoypad-3.4.1/src/joypad.cpp at line 117 column 12: QTextStream -> Q3TextStream
In file /home/john/qjoypad-3.4.1/src/joypad.cpp at line 117 column 33: QTextStream -> Q3TextStream
In file /home/john/qjoypad-3.4.1/src/joypad.cpp at line 117 column 55: IO_WriteOnly -> QIODevice::WriteOnly
In file /home/john/qjoypad-3.4.1/src/joypad.cpp at line 119 column 26: QIntDictIterator -> Q3IntDictIterator
In file /home/john/qjoypad-3.4.1/src/joypad.cpp at line 126 column 26: QIntDictIterator -> Q3IntDictIterator
In file /home/john/qjoypad-3.4.1/src/joypad.cpp at line 139 column 26: QIntDictIterator -> Q3IntDictIterator
In file /home/john/qjoypad-3.4.1/src/joypad.cpp at line 142 column 26: QIntDictIterator -> Q3IntDictIterator
In file /home/john/qjoypad-3.4.1/src/joypad.cpp: Added the following include directives:
#include <Q3TextStream>
In file /home/john/qjoypad-3.4.1/src/joypadw.cpp at line 10 column 24: QGridLayout -> Q3GridLayout
In file /home/john/qjoypad-3.4.1/src/joypadw.cpp: Added the following include directives:
#include <Q3GridLayout>
In file /home/john/qjoypad-3.4.1/src/joyslider.cpp at line 156 column 12: QPointArray -> Q3PointArray
In file /home/john/qjoypad-3.4.1/src/joyslider.cpp: Added the following include directives:
#include <QResizeEvent> #include <Q3PointArray> #include <QMouseEvent> #include <QPaintEvent>
In file /home/john/qjoypad-3.4.1/src/keycode.cpp: Added the following include directives:
#include <QPixmap> #include <QPaintEvent>
In file /home/john/qjoypad-3.4.1/src/layout.cpp at line 13 column 26: QPopupMenu -> Q3PopupMenu
In file /home/john/qjoypad-3.4.1/src/layout.cpp at line 54 column 27: IO_ReadOnly -> QIODevice::ReadOnly
In file /home/john/qjoypad-3.4.1/src/layout.cpp at line 63 column 20: QIntDictIterator -> Q3IntDictIterator
In file /home/john/qjoypad-3.4.1/src/layout.cpp at line 69 column 12: QTextStream -> Q3TextStream
In file /home/john/qjoypad-3.4.1/src/layout.cpp at line 115 column 26: IO_ReadOnly -> QIODevice::ReadOnly
In file /home/john/qjoypad-3.4.1/src/layout.cpp at line 116 column 13: QTextStream -> Q3TextStream
In file /home/john/qjoypad-3.4.1/src/layout.cpp at line 137 column 22: QIntDictIterator -> Q3IntDictIterator
In file /home/john/qjoypad-3.4.1/src/layout.cpp at line 154 column 27: IO_WriteOnly -> QIODevice::WriteOnly
In file /home/john/qjoypad-3.4.1/src/layout.cpp at line 155 column 13: QTextStream -> Q3TextStream
In file /home/john/qjoypad-3.4.1/src/layout.cpp at line 157 column 23: QIntDictIterator -> Q3IntDictIterator
In file /home/john/qjoypad-3.4.1/src/layout.cpp at line 194 column 27: IO_WriteOnly -> QIODevice::WriteOnly
In file /home/john/qjoypad-3.4.1/src/layout.cpp at line 195 column 13: QTextStream -> Q3TextStream
In file /home/john/qjoypad-3.4.1/src/layout.cpp at line 276 column 17: QIntDictIterator -> Q3IntDictIterator
In file /home/john/qjoypad-3.4.1/src/layout.cpp: Added the following include directives:
#include <QPixmap> #include <Q3TextStream> #include <Q3PopupMenu>
In file /home/john/qjoypad-3.4.1/src/layout_edit.cpp at line 17 column 24: QVBoxLayout -> Q3VBoxLayout
In file /home/john/qjoypad-3.4.1/src/layout_edit.cpp at line 19 column 7: QFrame -> Q3Frame
In file /home/john/qjoypad-3.4.1/src/layout_edit.cpp at line 19 column 27: QFrame -> Q3Frame
In file /home/john/qjoypad-3.4.1/src/layout_edit.cpp at line 20 column 28: QFrame -> Q3Frame
In file /home/john/qjoypad-3.4.1/src/layout_edit.cpp at line 20 column 42: QFrame -> Q3Frame
In file /home/john/qjoypad-3.4.1/src/layout_edit.cpp at line 21 column 12: QGridLayout -> Q3GridLayout
In file /home/john/qjoypad-3.4.1/src/layout_edit.cpp at line 21 column 33: QGridLayout -> Q3GridLayout
In file /home/john/qjoypad-3.4.1/src/layout_edit.cpp at line 42 column 28: QWidgetStack -> Q3WidgetStack
In file /home/john/qjoypad-3.4.1/src/layout_edit.cpp at line 43 column 31: QFrame -> Q3Frame
In file /home/john/qjoypad-3.4.1/src/layout_edit.cpp at line 43 column 45: QFrame -> Q3Frame
In file /home/john/qjoypad-3.4.1/src/layout_edit.cpp at line 52 column 20: QIntDictIterator -> Q3IntDictIterator
In file /home/john/qjoypad-3.4.1/src/layout_edit.cpp at line 77 column 12: QHBoxLayout -> Q3HBoxLayout
In file /home/john/qjoypad-3.4.1/src/layout_edit.cpp at line 77 column 33: QHBoxLayout -> Q3HBoxLayout
In file /home/john/qjoypad-3.4.1/src/layout_edit.cpp at line 112 column 17: QIntDictIterator -> Q3IntDictIterator
In file /home/john/qjoypad-3.4.1/src/layout_edit.cpp: Added the following include directives:
#include <QPixmap> #include <Q3GridLayout> #include <Q3HBoxLayout> #include <Q3VBoxLayout> #include <Q3Frame>
In file /home/john/qjoypad-3.4.1/src/loop.cpp at line 21 column 17: QIntDictIterator -> Q3IntDictIterator
In file /home/john/qjoypad-3.4.1/src/loop.cpp: Added the following include directives:
#include <QTimerEvent> #include <QEventLoop>
In file /home/john/qjoypad-3.4.1/src/main.cpp at line 34 column 8: QIntDict -> Q3IntDict
In file /home/john/qjoypad-3.4.1/src/main.cpp at line 35 column 8: QIntDict -> Q3IntDict
In file /home/john/qjoypad-3.4.1/src/main.cpp at line 36 column 8: QPtrList -> Q3PtrList
In file /home/john/qjoypad-3.4.1/src/main.cpp at line 56 column 20: QIntDictIterator -> Q3IntDictIterator
In file /home/john/qjoypad-3.4.1/src/main.cpp at line 192 column 28: IO_WriteOnly -> QIODevice::WriteOnly
In file /home/john/qjoypad-3.4.1/src/main.cpp at line 194 column 14: QTextStream -> Q3TextStream
In file /home/john/qjoypad-3.4.1/src/main.cpp at line 210 column 33: IO_ReadOnly -> QIODevice::ReadOnly
In file /home/john/qjoypad-3.4.1/src/main.cpp at line 213 column 14: QTextStream -> Q3TextStream
In file /home/john/qjoypad-3.4.1/src/main.cpp at line 235 column 31: IO_WriteOnly -> QIODevice::WriteOnly
In file /home/john/qjoypad-3.4.1/src/main.cpp at line 237 column 13: QTextStream -> Q3TextStream
In file /home/john/qjoypad-3.4.1/src/main.cpp: Added the following include directives:
#include <Q3TextStream> #include <Q3PtrList>
In file /home/john/qjoypad-3.4.1/src/quickset.cpp at line 12 column 12: QVBoxLayout -> Q3VBoxLayout
In file /home/john/qjoypad-3.4.1/src/quickset.cpp at line 12 column 37: QVBoxLayout -> Q3VBoxLayout
In file /home/john/qjoypad-3.4.1/src/quickset.cpp: Added the following include directives:
#include <Q3VBoxLayout> #include <QLabel>
Log for qt3to4 on Fri Dec 26 19:23:39 2008. Number of log entries: 47
In file /home/john/qjoypad-3.4.1/src/axis.h at line 30 column 24: QTextStream -> Q3TextStream
In file /home/john/qjoypad-3.4.1/src/axis.h at line 32 column 25: QTextStream -> Q3TextStream
In file /home/john/qjoypad-3.4.1/src/axis.h: Added the following include directives:
#include <Q3TextStream>
In file /home/john/qjoypad-3.4.1/src/axis_edit.h at line 8 column 16: qframe.h -> q3frame.h
In file /home/john/qjoypad-3.4.1/src/axis_edit.h at line 40 column 8: QFrame -> Q3Frame
In file /home/john/qjoypad-3.4.1/src/axisw.h: Added the following include directives:
#include <QMouseEvent>
In file /home/john/qjoypad-3.4.1/src/button.h at line 23 column 24: QTextStream -> Q3TextStream
In file /home/john/qjoypad-3.4.1/src/button.h at line 25 column 25: QTextStream -> Q3TextStream
In file /home/john/qjoypad-3.4.1/src/button.h: Added the following include directives:
#include <Q3TextStream>
No changes made to file /home/john/qjoypad-3.4.1/src/button_edit.h
In file /home/john/qjoypad-3.4.1/src/buttonw.h: Added the following include directives:
#include <QMouseEvent>
In file /home/john/qjoypad-3.4.1/src/component.h at line 7 column 21: qtextstream.h -> q3textstream.h
In file /home/john/qjoypad-3.4.1/src/component.h at line 21 column 32: QTextStream -> Q3TextStream
In file /home/john/qjoypad-3.4.1/src/component.h at line 22 column 33: QTextStream -> Q3TextStream
No changes made to file /home/john/qjoypad-3.4.1/src/constant.h
In file /home/john/qjoypad-3.4.1/src/device.h at line 4 column 18: qintdict.h -> q3intdict.h
In file /home/john/qjoypad-3.4.1/src/device.h at line 11 column 15: QIntDict -> Q3IntDict
In file /home/john/qjoypad-3.4.1/src/device.h at line 15 column 15: QIntDict -> Q3IntDict
In file /home/john/qjoypad-3.4.1/src/error.h at line 10 column 39: QMessageBox -> Qt
No changes made to file /home/john/qjoypad-3.4.1/src/event.h
In file /home/john/qjoypad-3.4.1/src/flash.h at line 75 column 12: QBoxLayout -> Q3BoxLayout
In file /home/john/qjoypad-3.4.1/src/flash.h: Added the following include directives:
#include <Q3BoxLayout>
In file /home/john/qjoypad-3.4.1/src/icon.h at line 16 column 16: QPopupMenu -> Q3PopupMenu
In file /home/john/qjoypad-3.4.1/src/icon.h at line 21 column 47: QPopupMenu -> Q3PopupMenu
In file /home/john/qjoypad-3.4.1/src/icon.h at line 28 column 12: QPopupMenu -> Q3PopupMenu
In file /home/john/qjoypad-3.4.1/src/icon.h: Added the following include directives:
#include <QCloseEvent> #include <Q3PopupMenu> #include <QMouseEvent>
In file /home/john/qjoypad-3.4.1/src/joypad.h at line 7 column 18: qintdict.h -> q3intdict.h
In file /home/john/qjoypad-3.4.1/src/joypad.h at line 38 column 24: QTextStream -> Q3TextStream
In file /home/john/qjoypad-3.4.1/src/joypad.h at line 40 column 25: QTextStream -> Q3TextStream
In file /home/john/qjoypad-3.4.1/src/joypad.h at line 71 column 10: QIntDict -> Q3IntDict
In file /home/john/qjoypad-3.4.1/src/joypad.h at line 72 column 10: QIntDict -> Q3IntDict
In file /home/john/qjoypad-3.4.1/src/joypad.h: Added the following include directives:
#include <Q3TextStream>
In file /home/john/qjoypad-3.4.1/src/joypadw.h at line 58 column 13: QGridLayout -> Q3GridLayout
In file /home/john/qjoypad-3.4.1/src/joypadw.h: Added the following include directives:
#include <Q3GridLayout>
In file /home/john/qjoypad-3.4.1/src/joyslider.h: Added the following include directives:
#include <QPaintEvent> #include <QResizeEvent> #include <QMouseEvent>
In file /home/john/qjoypad-3.4.1/src/keycode.h: Added the following include directives:
#include <QPaintEvent>
In file /home/john/qjoypad-3.4.1/src/layout.h at line 7 column 21: qtextstream.h -> q3textstream.h
In file /home/john/qjoypad-3.4.1/src/layout.h at line 18 column 21: qpopupmenu.h -> q3popupmenu.h
In file /home/john/qjoypad-3.4.1/src/layout.h at line 90 column 12: QPopupMenu -> Q3PopupMenu
In file /home/john/qjoypad-3.4.1/src/layout_edit.h at line 10 column 22: qwidgetstack.h -> q3widgetstack.h
In file /home/john/qjoypad-3.4.1/src/layout_edit.h at line 39 column 13: QVBoxLayout -> Q3VBoxLayout
In file /home/john/qjoypad-3.4.1/src/layout_edit.h at line 40 column 14: QWidgetStack -> Q3WidgetStack
In file /home/john/qjoypad-3.4.1/src/layout_edit.h: Added the following include directives:
#include <Q3VBoxLayout>
In file /home/john/qjoypad-3.4.1/src/loop.h at line 39 column 10: QPtrList -> Q3PtrList
In file /home/john/qjoypad-3.4.1/src/loop.h: Added the following include directives:
#include <Q3PtrList> #include <QTimerEvent>
No changes made to file /home/john/qjoypad-3.4.1/src/quickset.h
No changes made to file /home/john/qjoypad-3.4.1/src/timer.h
Log for qt3to4 on Fri Dec 26 19:24:31 2008. Number of log entries: 1
No changes made to file /home/john/qjoypad-3.4.1/src/Makefile

BIN
src/qjoypad Executable file

Binary file not shown.

87
src/qjoypad.pro Normal file
View File

@ -0,0 +1,87 @@
########################################
# #
# QMake project file for QJoyPad #
# #
########################################
##### Setup Targets #####
target.path = $$PREFIX/bin
icons.path = $$PREFIX/share/pixmaps/qjoypad
icons.extra = cp ../icons/* $${icons.path}; cd $${icons.path}; ln -sf gamepad4-24x24.png icon24.png; ln -sf gamepad3-64x64.png icon64.png; chmod -R a+r $${icons.path}
doc.path = $$PREFIX/doc/qjoypad3
doc.extra = cp ../README.txt ../LICENSE.txt $${doc.path}
##### Setup Compile #####
DEFINES += DEVDIR='"$$DEVDIR"'
DEFINES += ICON24='\"$${icons.path}/icon24.png\"'
DEFINES += ICON64='\"$${icons.path}/icon64.png\"'
TEMPLATE = app
DEPENDPATH += trayicon
INCLUDEPATH += . trayicon
QMAKE_LIBS += -lXtst
# Input
HEADERS += axis.h \
axis_edit.h \
axisw.h \
button.h \
button_edit.h \
buttonw.h \
constant.h \
device.h \
error.h \
event.h \
flash.h \
icon.h \
joypad.h \
joypadw.h \
joyslider.h \
keycode.h \
layout.h \
getkey.h \
layout_edit.h \
quickset.h \
trayicon/trayicon.h
SOURCES += axis.cpp \
axis_edit.cpp \
axisw.cpp \
button.cpp \
button_edit.cpp \
buttonw.cpp \
event.cpp \
flash.cpp \
icon.cpp \
joypad.cpp \
joypadw.cpp \
joyslider.cpp \
keycode.cpp \
layout.cpp \
layout_edit.cpp \
main.cpp \
quickset.cpp \
getkey.cpp \
trayicon/trayicon.cpp \
trayicon/trayicon_x11.cpp
##### Install #####
INSTALLS += target icons doc

89
src/qjoypad.pro.backup Normal file
View File

@ -0,0 +1,89 @@
########################################
# #
# QMake project file for QJoyPad #
# #
########################################
##### Setup Targets #####
target.path = $$PREFIX/bin
icons.path = $$PREFIX/share/pixmaps/qjoypad
icons.extra = cp ../icons/* $${icons.path}; cd $${icons.path}; ln -sf gamepad4-24x24.png icon24.png; ln -sf gamepad3-64x64.png icon64.png; chmod -R a+r $${icons.path}
doc.path = $$PREFIX/doc/qjoypad3
doc.extra = cp ../README.txt ../LICENSE.txt $${doc.path}
##### Setup Compile #####
DEFINES += DEVDIR='"$$DEVDIR"'
DEFINES += ICON24='"$${icons.path}/icon24.png"'
DEFINES += ICON64='"$${icons.path}/icon64.png"'
TEMPLATE = app
DEPENDPATH += trayicon
INCLUDEPATH += . trayicon
QMAKE_LIBS += -lXtst
# Input
HEADERS += axis.h \
axis_edit.h \
axisw.h \
button.h \
button_edit.h \
buttonw.h \
component.h \
constant.h \
device.h \
error.h \
event.h \
flash.h \
icon.h \
joypad.h \
joypadw.h \
joyslider.h \
keycode.h \
layout.h \
layout_edit.h \
loop.h \
quickset.h \
timer.h \
trayicon/trayicon.h
SOURCES += axis.cpp \
axis_edit.cpp \
axisw.cpp \
button.cpp \
button_edit.cpp \
buttonw.cpp \
event.cpp \
flash.cpp \
icon.cpp \
joypad.cpp \
joypadw.cpp \
joyslider.cpp \
keycode.cpp \
layout.cpp \
layout_edit.cpp \
loop.cpp \
main.cpp \
quickset.cpp \
trayicon/trayicon.cpp \
trayicon/trayicon_x11.cpp
##### Install #####
INSTALLS += target icons doc

57
src/quickset.cpp Normal file
View File

@ -0,0 +1,57 @@
#include "quickset.h"
#include "getkey.h"
//build the dialog
QuickSet::QuickSet( JoyPad* jp)
: QDialog() {
setting = false;
joypad = jp;
setWindowTitle("Set " + jp->getName());
QVBoxLayout* LMain = new QVBoxLayout(this);
LMain->setMargin(5);
LMain->setSpacing(5);
//LMain->setAutoAdd(true);
new QLabel("Press any button or axis and\nyou will be prompted for a key.",this);
QPushButton* button = new QPushButton("Done",this);
connect( button, SIGNAL(clicked()), this, SLOT(accept()));
}
void QuickSet::jsevent( js_event msg ) {
//ignore any joystick events if we're waiting for a keypress
if (setting) return;
//if a button was pressed on the joystick
if (msg.type == JS_EVENT_BUTTON) {
//capture that button.
Button* button = joypad->Buttons[msg.number];
//go into setting mode and request a key/mousebutton
setting = true;
int code = GetKey(button->getName(), true).exec();
setting = false;
//if a mouse button was used,
if (code > MOUSE_OFFSET)
//then tell it to the Button a mouse button
button->setKey(true, code - MOUSE_OFFSET);
else
//otherwise, tell it to use a keycode.
button->setKey(false, code);
}
else {
//require a signal strength of at least 5000 to consider an axis moved.
if (abs(msg.value) < 5000) return;
//capture the axis that moved
Axis* axis = joypad->Axes[msg.number];
//grab a keycode for that axis and that direction
setting = true;
int code = GetKey(axis->getName() + ", " + QString((msg.value > 0)?"positive":"negative"), false).exec();
setting = false;
//assign the key to the axis.
axis->setKey((msg.value > 0),code);
}
}

33
src/quickset.h Normal file
View File

@ -0,0 +1,33 @@
#ifndef QUICKSET_H
#define QUICKSET_H
//for building the dialog
#include <QLayout>
#include <QLabel>
#include <QPushButton>
#include <linux/joystick.h>
//to request new keycodes
//#include "keycode.h"
//to actually set the joypad
#include "joypad.h"
//because of some circularity issues ;)
class JoyPad;
//a dialog to quickly set a key to a button
class QuickSet : public QDialog {
public:
QuickSet(JoyPad* jp);
//this needs to see js_events so it can capture them directly
void jsevent( js_event msg );
private:
//the joypad that is being configured
JoyPad* joypad;
//when a joystick event has trigered QuickSet, setting is true and it
//is waiting for a keypress or mouse click. Otherwise, setting is false.
bool setting;
};
#endif

275
src/trayicon/trayicon.cpp Normal file
View File

@ -0,0 +1,275 @@
/*
* trayicon.cpp - system-independent trayicon class (adapted from Qt example)
* Copyright (C) 2003 Justin Karneges
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#include "trayicon.h"
/*!
\class TrayIcon qtrayicon.h
\brief The TrayIcon class implements an entry in the system tray.
*/
/*!
Creates a TrayIcon object. \a parent and \a name are propagated
to the QObject constructor. The icon is initially invisible.
\sa show
*/
TrayIcon::TrayIcon( QObject *parent, const char *name )
: QObject(parent/*, name*/), pop(0), d(0)
{
v_isWMDock = FALSE;
}
/*!
Creates a TrayIcon object displaying \a icon and \a tooltip, and opening
\a popup when clicked with the right mousebutton. \a parent and \a name are
propagated to the QObject constructor. The icon is initially invisible.
\sa show
*/
TrayIcon::TrayIcon( const QPixmap &icon, const QString &tooltip, QMenu *popup, QObject *parent, const char *name )
: QObject(parent/*, name*/), pop(popup), pm(icon), tip(tooltip), d(0)
{
v_isWMDock = FALSE;
}
/*!
Removes the icon from the system tray and frees all allocated resources.
*/
TrayIcon::~TrayIcon()
{
sysRemove();
}
/*!
Sets the context menu to \a popup. The context menu will pop up when the
user clicks the system tray entry with the right mouse button.
*/
void TrayIcon::setPopup( QMenu* popup )
{
pop = popup;
}
/*!
Returns the current popup menu.
\sa setPopup
*/
QMenu* TrayIcon::popup() const
{
return pop;
}
/*!
\property TrayIcon::icon
\brief the system tray icon.
*/
void TrayIcon::setIcon( const QPixmap &icon )
{
//if(!popup()) {
// tip = "";
//}
pm = icon;
sysUpdateIcon();
}
QPixmap TrayIcon::icon() const
{
return pm;
}
/*!
\property TrayIcon::toolTip
\brief the tooltip for the system tray entry
On some systems, the tooltip's length is limited and will be truncated as necessary.
*/
void TrayIcon::setToolTip( const QString &tooltip )
{
tip = tooltip;
sysUpdateToolTip();
}
QString TrayIcon::toolTip() const
{
return tip;
}
/*!
Shows the icon in the system tray.
\sa hide
*/
void TrayIcon::show()
{
sysInstall();
}
/*!
Hides the system tray entry.
*/
void TrayIcon::hide()
{
sysRemove();
}
/*!
\reimp
*/
bool TrayIcon::event( QEvent *e )
{
switch ( e->type() ) {
case QEvent::MouseMove:
mouseMoveEvent( (QMouseEvent*)e );
break;
case QEvent::MouseButtonPress:
mousePressEvent( (QMouseEvent*)e );
break;
case QEvent::MouseButtonRelease:
mouseReleaseEvent( (QMouseEvent*)e );
break;
case QEvent::MouseButtonDblClick:
mouseDoubleClickEvent( (QMouseEvent*)e );
break;
default:
return QObject::event( e );
}
return TRUE;
}
/*!
This event handler can be reimplemented in a subclass to receive
mouse move events for the system tray entry.
\sa mousePressEvent(), mouseReleaseEvent(), mouseDoubleClickEvent(), QMouseEvent
*/
void TrayIcon::mouseMoveEvent( QMouseEvent *e )
{
e->ignore();
}
/*!
This event handler can be reimplemented in a subclass to receive
mouse press events for the system tray entry.
\sa mouseReleaseEvent(), mouseDoubleClickEvent(),
mouseMoveEvent(), QMouseEvent
*/
void TrayIcon::mousePressEvent( QMouseEvent *e )
{
#ifndef Q_WS_WIN
// This is for X11, menus appear on mouse press
// I'm not sure whether Mac should be here or below.. Somebody check?
switch ( e->button() ) {
case Qt::RightButton:
if ( pop ) {
pop->popup( e->globalPos() );
e->accept();
}
break;
case Qt::LeftButton:
case Qt::MidButton:
emit clicked( e->globalPos(), e->button() );
break;
default:
break;
}
#endif
e->ignore();
}
/*!
This event handler can be reimplemented in a subclass to receive
mouse release events for the system tray entry.
The default implementations opens the context menu when the entry
has been clicked with the right mouse button.
\sa setPopup(), mousePressEvent(), mouseDoubleClickEvent(),
mouseMoveEvent(), QMouseEvent
*/
void TrayIcon::mouseReleaseEvent( QMouseEvent *e )
{
#ifdef Q_WS_WIN
// This is for Windows, where menus appear on mouse release
switch ( e->button() ) {
case Qt::RightButton:
if ( pop ) {
// Necessary to make keyboard focus
// and menu closing work on Windows.
pop->setActiveWindow();
pop->popup( e->globalPos() );
pop->setActiveWindow();
e->accept();
}
break;
case Qt::LeftButton:
case Qt::MidButton:
emit clicked( e->globalPos(), e->button() );
break;
default:
break;
}
#endif
e->ignore();
}
/*!
This event handler can be reimplemented in a subclass to receive
mouse double click events for the system tray entry.
Note that the system tray entry gets a mousePressEvent() and a
mouseReleaseEvent() before the mouseDoubleClickEvent().
\sa mousePressEvent(), mouseReleaseEvent(),
mouseMoveEvent(), QMouseEvent
*/
void TrayIcon::mouseDoubleClickEvent( QMouseEvent *e )
{
if ( e->button() == Qt::LeftButton )
emit doubleClicked( e->globalPos() );
e->accept();
}
/*!
\fn void TrayIcon::clicked( const QPoint &p )
This signal is emitted when the user clicks the system tray icon
with the left mouse button, with \a p being the global mouse position
at that moment.
*/
/*!
\fn void TrayIcon::doubleClicked( const QPoint &p )
This signal is emitted when the user double clicks the system tray
icon with the left mouse button, with \a p being the global mouse position
at that moment.
*/
void TrayIcon::gotCloseEvent()
{
closed();
}

96
src/trayicon/trayicon.h Executable file
View File

@ -0,0 +1,96 @@
/*
* trayicon.h - system-independent trayicon class (adapted from Qt example)
* Copyright (C) 2003 Justin Karneges
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#ifndef CS_TRAYICON_H
#define CS_TRAYICON_H
#include <qobject.h>
#include <qimage.h>
#include <QPixmap>
#include <QDir>
#include <QMenu>
#include <QMouseEvent>
class TrayIcon : public QObject
{
Q_OBJECT
Q_PROPERTY( QString toolTip READ toolTip WRITE setToolTip )
Q_PROPERTY( QPixmap icon READ icon WRITE setIcon )
public:
TrayIcon( QObject *parent = 0, const char *name = 0 );
TrayIcon( const QPixmap &, const QString &, QMenu *popup = 0, QObject *parent = 0, const char *name = 0 );
~TrayIcon();
// use WindowMaker dock mode. ignored on non-X11 platforms
void setWMDock(bool use) { v_isWMDock = use; }
bool isWMDock() { return v_isWMDock; }
// Set a popup menu to handle RMB
void setPopup( QMenu * );
QMenu* popup() const;
QPixmap icon() const;
QString toolTip() const;
void gotCloseEvent();
public slots:
void setIcon( const QPixmap &icon );
void setToolTip( const QString &tip );
void show();
void hide();
signals:
void clicked( const QPoint&, int);
void doubleClicked( const QPoint& );
void closed();
protected:
bool event( QEvent * );
virtual void mouseMoveEvent( QMouseEvent *e );
virtual void mousePressEvent( QMouseEvent *e );
virtual void mouseReleaseEvent( QMouseEvent *e );
virtual void mouseDoubleClickEvent( QMouseEvent *e );
private:
QMenu *pop;
QPixmap pm;
QString tip;
bool v_isWMDock;
// system-dependant part
public:
class TrayIconPrivate;
private:
TrayIconPrivate *d;
void sysInstall();
void sysRemove();
void sysUpdateIcon();
void sysUpdateToolTip();
friend class TrayIconPrivate;
};
#endif // CS_TRAYICON_H

View File

@ -0,0 +1,374 @@
/*
* trayicon_x11.cpp - X11 trayicon (for use with KDE and GNOME)
* Copyright (C) 2003 Justin Karneges
* GNOME2 Notification Area support: Tomasz Sterna
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#include "trayicon.h"
#include <QX11Info>
#include <QApplication>
#include <QPainter>
#include<X11/Xlib.h>
#include<X11/Xutil.h>
#include<X11/Xatom.h>
//#if QT_VERSION < 0x030200
//extern Time;// qt_x_time;
//#endif
//----------------------------------------------------------------------------
// common stuff
//----------------------------------------------------------------------------
// for Gnome2 Notification Area
static XErrorHandler old_handler = 0;
static int dock_xerror = 0;
extern "C" int dock_xerrhandler(Display* dpy, XErrorEvent* err)
{
dock_xerror = err->error_code;
return old_handler(dpy, err);
}
static void trap_errors()
{
dock_xerror = 0;
old_handler = XSetErrorHandler(dock_xerrhandler);
}
static bool untrap_errors()
{
XSetErrorHandler(old_handler);
return (dock_xerror == 0);
}
static bool send_message(
Display* dpy, /* display */
Window w, /* sender (tray icon window) */
long message, /* message opcode */
long data1, /* message data 1 */
long data2, /* message data 2 */
long data3 /* message data 3 */
) {
XEvent ev;
memset(&ev, 0, sizeof(ev));
ev.xclient.type = ClientMessage;
ev.xclient.window = w;
ev.xclient.message_type = XInternAtom (dpy, "_NET_SYSTEM_TRAY_OPCODE", False );
ev.xclient.format = 32;
ev.xclient.data.l[0] = CurrentTime;
ev.xclient.data.l[1] = message;
ev.xclient.data.l[2] = data1;
ev.xclient.data.l[3] = data2;
ev.xclient.data.l[4] = data3;
trap_errors();
XSendEvent(dpy, w, False, NoEventMask, &ev);
XSync(dpy, False);
return untrap_errors();
}
#define SYSTEM_TRAY_REQUEST_DOCK 0
#define SYSTEM_TRAY_BEGIN_MESSAGE 1
#define SYSTEM_TRAY_CANCEL_MESSAGE 2
//----------------------------------------------------------------------------
// TrayIcon::TrayIconPrivate
//----------------------------------------------------------------------------
class TrayIcon::TrayIconPrivate : public QWidget
{
public:
TrayIconPrivate(TrayIcon *object, int size);
~TrayIconPrivate() { }
virtual void initWM(WId icon);
virtual void setPixmap(const QPixmap &pm);
virtual void paintEvent(QPaintEvent *);
virtual void enterEvent(QEvent *);
virtual void mouseMoveEvent(QMouseEvent *e);
virtual void mousePressEvent(QMouseEvent *e);
virtual void mouseReleaseEvent(QMouseEvent *e);
virtual void mouseDoubleClickEvent(QMouseEvent *e);
virtual void closeEvent(QCloseEvent *e);
private:
TrayIcon *iconObject;
QPixmap pix;
int size;
};
TrayIcon::TrayIconPrivate::TrayIconPrivate(TrayIcon *object, int _size)
: QWidget(0/*, object->name(), Qt::WRepaintNoErase*/)
{
iconObject = object;
size = _size;
setAttribute(Qt::WA_NoBackground);
setFocusPolicy(Qt::NoFocus);
//setBackgroundMode(X11ParentRelative);
setMinimumSize(size, size);
setMaximumSize(size, size);
}
// This base stuff is required by both FreeDesktop specification and WindowMaker
void TrayIcon::TrayIconPrivate::initWM(WId icon)
{
Display *dsp = x11Info().display();
WId leader = winId();
// set the class hint
XClassHint classhint;
classhint.res_name = (char*)"psidock";
classhint.res_class = (char*)"Psi";
XSetClassHint(dsp, leader, &classhint);
// set the Window Manager hints
XWMHints *hints;
hints = XGetWMHints(dsp, leader); // init hints
hints->flags = WindowGroupHint | IconWindowHint | StateHint; // set the window group hint
hints->window_group = leader; // set the window hint
hints->initial_state = WithdrawnState; // initial state
hints->icon_window = icon; // in WM, this should be winId() of separate widget
hints->icon_x = 0;
hints->icon_y = 0;
XSetWMHints(dsp, leader, hints); // set the window hints for WM to use.
XFree( hints );
}
void TrayIcon::TrayIconPrivate::setPixmap(const QPixmap &pm)
{
pix = pm;
setWindowIcon(pix);
repaint();
}
void TrayIcon::TrayIconPrivate::paintEvent(QPaintEvent *)
{
QPainter p(this);
p.drawPixmap((width() - pix.width())/2, (height() - pix.height())/2, pix);
}
void TrayIcon::TrayIconPrivate::enterEvent(QEvent *e)
{
// Taken from KSystemTray..
//#if QT_VERSION < 0x030200
//if ( !qApp->focusWidget() ) {
XEvent ev;
memset(&ev, 0, sizeof(ev));
ev.xfocus.display = x11Info().display();//qt_xdisplay();
ev.xfocus.type = FocusIn;
ev.xfocus.window = winId();
ev.xfocus.mode = NotifyNormal;
ev.xfocus.detail = NotifyAncestor;
Time time = x11Info().appTime();//qt_x_time;
//qt_x_time = 1;
x11Info().setAppTime(1);
qApp->x11ProcessEvent( &ev );
//qt_x_time = time;
x11Info().setAppTime(time);
//}
//#endif
QWidget::enterEvent(e);
}
void TrayIcon::TrayIconPrivate::mouseMoveEvent(QMouseEvent *e)
{
QApplication::sendEvent(iconObject, e);
}
void TrayIcon::TrayIconPrivate::mousePressEvent(QMouseEvent *e)
{
QApplication::sendEvent(iconObject, e);
}
void TrayIcon::TrayIconPrivate::mouseReleaseEvent(QMouseEvent *e)
{
QApplication::sendEvent(iconObject, e);
}
void TrayIcon::TrayIconPrivate::mouseDoubleClickEvent(QMouseEvent *e)
{
QApplication::sendEvent(iconObject, e);
}
void TrayIcon::TrayIconPrivate::closeEvent(QCloseEvent *e)
{
iconObject->gotCloseEvent();
e->accept();
}
//----------------------------------------------------------------------------
// TrayIconFreeDesktop
//----------------------------------------------------------------------------
class TrayIconFreeDesktop : public TrayIcon::TrayIconPrivate
{
public:
TrayIconFreeDesktop(TrayIcon *object, const QPixmap &pm);
};
TrayIconFreeDesktop::TrayIconFreeDesktop(TrayIcon *object, const QPixmap &pm)
: TrayIconPrivate(object, 22)
{
initWM( winId() );
// initialize NetWM
Display *dsp = x11Info().display();//x11Display();
// dock the widget (adapted from SIM-ICQ)
Screen *screen = XDefaultScreenOfDisplay(dsp); // get the screen
int screen_id = XScreenNumberOfScreen(screen); // and it's number
char buf[32];
snprintf(buf, sizeof(buf), "_NET_SYSTEM_TRAY_S%d", screen_id);
Atom selection_atom = XInternAtom(dsp, buf, false);
XGrabServer(dsp);
Window manager_window = XGetSelectionOwner(dsp, selection_atom);
if ( manager_window != None )
XSelectInput(dsp, manager_window, StructureNotifyMask);
XUngrabServer(dsp);
XFlush(dsp);
if ( manager_window != None )
send_message(dsp, manager_window, SYSTEM_TRAY_REQUEST_DOCK, winId(), 0, 0);
// some KDE mumbo-jumbo... why is it there? anybody?
Atom kwm_dockwindow_atom = XInternAtom(dsp, "KWM_DOCKWINDOW", false);
Atom kde_net_system_tray_window_for_atom = XInternAtom(dsp, "_KDE_NET_WM_SYSTEM_TRAY_WINDOW_FOR", false);
long data = 0;
XChangeProperty(dsp, winId(), kwm_dockwindow_atom, kwm_dockwindow_atom, 32, PropModeReplace, (uchar*)&data, 1);
XChangeProperty(dsp, winId(), kde_net_system_tray_window_for_atom, XA_WINDOW, 32, PropModeReplace, (uchar*)&data, 1);
setPixmap(pm);
}
//----------------------------------------------------------------------------
// TrayIconWindowMaker
//----------------------------------------------------------------------------
class TrayIconWharf : public TrayIcon::TrayIconPrivate
{
public:
TrayIconWharf(TrayIcon *object, const QPixmap &pm)
: TrayIconPrivate(object, 64)
{
setPixmap(pm);
}
void setPixmap(const QPixmap &_pm)
{
QPixmap pm;
QImage i = _pm.toImage();
i = i.scaled(i.width() * 2, i.height() * 2);
pm = QPixmap::fromImage(i);
TrayIconPrivate::setPixmap(pm);
// thanks to Robert Spier for this:
// for some reason the repaint() isn't being honored, or isn't for
// the icon. So force one on the widget behind the icon
//erase();
QPaintEvent pe( rect() );
paintEvent(&pe);
}
};
class TrayIconWindowMaker : public TrayIcon::TrayIconPrivate
{
public:
TrayIconWindowMaker(TrayIcon *object, const QPixmap &pm);
~TrayIconWindowMaker();
void setPixmap(const QPixmap &pm);
private:
TrayIconWharf *wharf;
};
TrayIconWindowMaker::TrayIconWindowMaker(TrayIcon *object, const QPixmap &pm)
: TrayIconPrivate(object, 32)
{
wharf = new TrayIconWharf(object, pm);
initWM( wharf->winId() );
}
TrayIconWindowMaker::~TrayIconWindowMaker()
{
delete wharf;
}
void TrayIconWindowMaker::setPixmap(const QPixmap &pm)
{
wharf->setPixmap(pm);
}
//----------------------------------------------------------------------------
// TrayIcon
//----------------------------------------------------------------------------
void TrayIcon::sysInstall()
{
if ( d )
return;
if ( v_isWMDock )
d = (TrayIconPrivate *)(new TrayIconWindowMaker(this, pm));
else
d = (TrayIconPrivate *)(new TrayIconFreeDesktop(this, pm));
sysUpdateToolTip();
d->show();
}
void TrayIcon::sysRemove()
{
if ( !d )
return;
delete d;
d = 0;
}
void TrayIcon::sysUpdateIcon()
{
if ( !d )
return;
QPixmap pix = pm;
d->setPixmap(pix);
}
void TrayIcon::sysUpdateToolTip()
{
if ( !d )
return;
if ( tip.isEmpty() ) {
//QToolTip::remove(d);
d->setToolTip(QString());
} else {
//QToolTip::add(d, tip);
d->setToolTip(tip);
}
}