finishing up repo migration
git-svn-id: svn://svn.code.sf.net/p/qjoypad/code/trunk@80 c05e91a0-76c8-4ec0-b377-ef19ce7cc080
9
INSTALL.txt
Normal 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
@ -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
@ -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
After Width: | Height: | Size: 1.0 KiB |
BIN
icons/gamepad1-64x64.png
Normal file
After Width: | Height: | Size: 4.6 KiB |
BIN
icons/gamepad2-24x24.png
Normal file
After Width: | Height: | Size: 1.5 KiB |
BIN
icons/gamepad2-64x64.png
Normal file
After Width: | Height: | Size: 6.6 KiB |
BIN
icons/gamepad3-24x24.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
icons/gamepad3-64x64.png
Normal file
After Width: | Height: | Size: 5.1 KiB |
BIN
icons/gamepad4-24x24.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
icons/gamepad4-64x64.png
Normal file
After Width: | Height: | Size: 5.3 KiB |
30
src/.kdbgrc.qjoypad
Normal 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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
87
src/qjoypad.pro
Normal 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
@ -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
@ -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
@ -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
@ -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
@ -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
|
374
src/trayicon/trayicon_x11.cpp
Normal 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);
|
||||
}
|
||||
}
|