forked from Ports/goldeneye-pc-port
v0.3.0 release review: watchdog re-arm, rule-2 sign-offs, GPL source removal, repo hygiene
Per the 2026-09-19 adversarial pre-ship review (findings.md M-192): - d318watchdog.c: one-shot per OCCURRENCE, not per process -- re-arm after 600 ticks of signature absence so a Facility replay in the same session (AllUnlocked) is still covered. - model.c: RULE-2-SIGNOFF records for the retained M-183/M-185 and D311 defensive clamps (user-approved retention as the stability-maximizing option; stale 'Threshold: 50.0' comment corrected to 10.0f; both marked post-release removal candidates pending full cutscene re-verification). - reference/mouse-injector/: removed from the public repo (GPLv2 source + prebuilt discord-rpc.lib in an MIT project; never compiled here). Provenance stub README remains; path gitignored for local re-vendoring. AGENTS.md / GEPD-INPUT-PLAN.md / optionsoverlay.c refs updated. - scratch/: untracked + gitignored (19 session logs/probe sources were committed in the release window). - findings-index.csv: D317 (and 5 other stale rows) now CLOSED -- added CLOSED to gen_findings_index.py's verdict vocabulary. - docs: D310 perf gauge (no change warranted), GE_DEBUG_UNLOCKALL noted in security-and-fidelity-status.md, release notes gain the missing D318 watchdog bullet + FOV-clamp clarification. Build verified: ./build-pc.sh ntsc-final clean; gen_findings_index.py --check and gen_env_probes.py --check pass.
This commit is contained in:
1 parent
63315030f8
commit
b3b0ff74db
57 files changed
+157
-11732
No files matched your search
@@ -1,280 +0,0 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc., <http://fsf.org/>
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Lesser 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
|
||||
@@ -1,40 +1,28 @@
|
||||
# GEPD Edition — Mouse Injector (vendored reference source)
|
||||
# mouse-injector (removed from public repo)
|
||||
|
||||
Vendored **read-only reference** for the PC port's input layer. NOT compiled
|
||||
by our build; never modify it — treat it like `rsp/graphics/gmain.s`
|
||||
(ground truth we consult, not code we ship).
|
||||
The GEPD-Edition Mouse Injector source (GPLv2, ~1.5 MB including a prebuilt
|
||||
`discord-rpc.lib`) was vendored here as a read-only reference for the PC
|
||||
port's mouse-aim model, and **removed from the public repo on 2026-09-19**
|
||||
during the v0.3.0 release review: it is GPL-licensed code (plus a binary)
|
||||
inside an MIT-licensed project, and it is not compiled or linked by anything
|
||||
in this tree — it was consulted by developers only.
|
||||
|
||||
## Provenance
|
||||
## Provenance (if you need to re-vendor it locally)
|
||||
|
||||
Extracted from `source.tar.xz` inside the GEPD Edition 1964 bundle
|
||||
(`C:\Users\james\Games\Emulators\Nintendo 64\1964_GEPD_Edition\1964\`).
|
||||
The Mouse Injector is a Project64/1964 input plugin that emulates the N64
|
||||
controller from keyboard/mouse while injecting mouse-aim state directly into
|
||||
GoldenEye 007 / Perfect Dark game memory. License: **GPLv2** (see
|
||||
`LICENSE.TXT`; `manymouse/` carries its own license).
|
||||
- Project: "GEPD-Edition Mouse Injector" (GoldenEye 007 / Perfect Dark N64
|
||||
mouse-aim injection for emulators), GPLv2.
|
||||
- The file that mattered was `games/goldeneye.c` (~380 lines — the whole GE
|
||||
aim/hipfire/menu model), plus `device.c` (raw mouse polling) and
|
||||
`maindll.h` (tickrate units).
|
||||
|
||||
**Version skew:** the tarball is a mix of eras — `device.c`, `ui/` are from
|
||||
the 2014 v1.5d line; `games/goldeneye.c`, `maindll.h`, `maindll.c` are dated
|
||||
2021–22; the bundle's binary is a 2023 build with a few later additions. The
|
||||
aim *model* in `games/goldeneye.c` is stable across those versions and is the
|
||||
one we already mirrored (finding D194). Consult it for the model and
|
||||
constants, not as an exact match to any single release.
|
||||
## What replaced it in this repo
|
||||
|
||||
## Key files
|
||||
- The ported, calibrated result lives in `port/src/input.c` (the D194
|
||||
lineage; see `docs/dev/GEPD-INPUT-PLAN.md` for the design record, which
|
||||
quotes the model inline).
|
||||
- Historical findings that cite `reference/mouse-injector/...` paths
|
||||
(`docs/dev/findings.md`, D194/D214/etc.) remain accurate as written; the
|
||||
cited file content is preserved in those write-ups.
|
||||
|
||||
| File | What to look at |
|
||||
|---|---|
|
||||
| `games/goldeneye.c` | **The whole GE input/aim model.** `GE_Inject()` = hipfire direct camera write + tank + menu cursor; `GE_AimMode()` = crosshair-position aim (±5.159° limit, 72% edge threshold, 475/s scroll — the D194 source); `GE_Crouch()` = crouch-toggle state machine; `GE_Controller()` = button mapping (wheel→weapon macro, aim=B in menus); `GE_InjectHacks()` = ROM patches we do NOT port (reload key, FOV override) but which document intended behavior. |
|
||||
| `games/perfectdark.c` | PD analogue of the same model (radial menu, hoverbike, camspy). |
|
||||
| `device.c` / `manymouse/` | Raw-driver mouse polling + cursor lock (`SetCursorPos` cadence), wheel cooldown handling, multi-device mapping. |
|
||||
| `maindll.h` | `TICKRATE`/`TIMESTEP` (2 ms overclocked / 4 ms stock) — the units every per-tick constant in `goldeneye.c` assumes. |
|
||||
| `global.h` | Settings enum (sensitivity range 1..80, acceleration, crosshair-movement %, invert pitch, crouch toggle, aim mode). |
|
||||
| `vkey.h` | Default key layout (WASD=C-buttons, Q=A, E=B, R=reload, wheel=weapon cycle). |
|
||||
|
||||
## Cross-references in our tree
|
||||
|
||||
- `docs/dev/GEPD-INPUT-PLAN.md` — plan for the remaining GEPD inheritances
|
||||
(issues #89/#90).
|
||||
- `port/src/input.c` — D194 (`aimGepdCompute`) is our mirror of
|
||||
`GE_AimMode()`; D223 wheel cycling mirrors `GE_Controller()`'s weapon macro.
|
||||
- `docs/dev/findings.md` §D194/D238 — aim-mode history and tuning.
|
||||
If you want the original source again for reference work, clone it locally
|
||||
into `reference/mouse-injector/` (it is gitignored now) — do not commit it.
|
||||
@@ -1,320 +0,0 @@
|
||||
//==========================================================================
|
||||
// Mouse Injector Plugin
|
||||
//==========================================================================
|
||||
// Copyright (C) 2016-2021 Carnivorous
|
||||
// All rights reserved.
|
||||
//
|
||||
// Mouse Injector 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, visit http://www.gnu.org/licenses/gpl-2.0.html
|
||||
//==========================================================================
|
||||
#include <stdlib.h>
|
||||
#include <windows.h>
|
||||
#include "global.h"
|
||||
#include "device.h"
|
||||
#include "maindll.h"
|
||||
#include "./manymouse/manymouse.h"
|
||||
#include "./games/game.h"
|
||||
|
||||
#define VK_LBUTTON 0x01 // IDs from vkey.h
|
||||
#define VK_RBUTTON 0x02
|
||||
#define VK_MBUTTON 0x04
|
||||
#define VK_XBUTTON1 0x05
|
||||
#define VK_XBUTTON2 0x06
|
||||
#define VK_WHEELUP 0x0A
|
||||
#define VK_WHEELDOWN 0x0B
|
||||
#define VK_WHEELLEFT 0x0E
|
||||
#define VK_WHEELRIGHT 0x0F
|
||||
|
||||
static int alreadyexec = 0; // has init already exec?
|
||||
static int connected = 0; // number of devices connected
|
||||
static POINT lockpos = {0}; // coords for mouse lock position
|
||||
|
||||
int windowactive = 1; // is emulator window active?
|
||||
|
||||
int DEV_Init(void);
|
||||
void DEV_Quit(void);
|
||||
DWORD WINAPI DEV_InjectThread();
|
||||
int DEV_ReturnKey(void);
|
||||
int DEV_ReturnDeviceID(const int devicetype);
|
||||
const char *DEV_Name(const int id);
|
||||
int DEV_Type(const int id);
|
||||
int DEV_TypeIndex(const int id);
|
||||
int DEV_TypeID(const int id, const int devicetype);
|
||||
|
||||
//==========================================================================
|
||||
// Purpose: First called upon device launch, returns total connected ms/kb
|
||||
// Changes Globals: alreadyexec, connected
|
||||
//==========================================================================
|
||||
int DEV_Init(void)
|
||||
{
|
||||
if(!alreadyexec)
|
||||
{
|
||||
alreadyexec = 1;
|
||||
connected = ManyMouse_Init();
|
||||
int activemice = 0, activekeyboards = 0;
|
||||
for(int index = 0; index < connected; index++)
|
||||
{
|
||||
if(DEV_Type(index) == MOUSETYPE)
|
||||
activemice = 1;
|
||||
else
|
||||
activekeyboards = 1;
|
||||
}
|
||||
if(!activemice || !activekeyboards) // fail if mouse or keyboard not detected (mouse and keyboard are required for this plugin)
|
||||
connected = 0;
|
||||
}
|
||||
if(connected >= 2) // if at least one mouse and keyboard are detected
|
||||
return connected;
|
||||
return 0;
|
||||
}
|
||||
//==========================================================================
|
||||
// Purpose: Safely close ManyMouse
|
||||
// Changes Globals: alreadyexec, connected
|
||||
//==========================================================================
|
||||
void DEV_Quit(void)
|
||||
{
|
||||
ManyMouse_Quit();
|
||||
alreadyexec = 0;
|
||||
connected = 0;
|
||||
}
|
||||
//==========================================================================
|
||||
// Purpose: Polls ManyMouse for input and injects into game
|
||||
// Changes Globals: a lot
|
||||
//==========================================================================
|
||||
DWORD WINAPI DEV_InjectThread()
|
||||
{
|
||||
ManyMouseEvent event; // hold current input event (movement, buttons, ect)
|
||||
memset(&DEVICE, 0, sizeof(DEVICE)); // clear device struct
|
||||
int checkwindowtick = 0; // check if emulator window is in focus
|
||||
int togglebuffer = 0; // buffer cool down for mouse toggle
|
||||
int acceptalldevices = 0; // accept all device input (used if only 1 player is active)
|
||||
unsigned char lockmousecounter = 0; // limit SetCursorPos execution
|
||||
while(ManyMouse_PollEvent(&event)) // flush message pump (max messages is 1024)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
while(!stopthread)
|
||||
{
|
||||
if(mousetoggle && lockmousecounter % (emuoverclock ? TICKRATE_STOCK : TICKRATE_OC) == 0) // don't execute every tick
|
||||
SetCursorPos(lockpos.x, lockpos.y); // set mouse position to lock position
|
||||
lockmousecounter++; // overflow pseudo-counter
|
||||
if(togglebuffer > 0)
|
||||
togglebuffer--;
|
||||
for(int player = PLAYER1; player < ALLPLAYERS; player++)
|
||||
{
|
||||
DEVICE[player].XPOS = 0, DEVICE[player].YPOS = 0; // reset mouse input
|
||||
if(DEVICE[player].WHEEL <= 1) // mouse wheel is not an instant key - treat with cooldown and turn button off once cooled off
|
||||
{
|
||||
DEVICE[player].WHEEL = 0;
|
||||
for(int button = 0; button < TOTALBUTTONS; button++) // reset wheel scroll once cooled down
|
||||
{
|
||||
if(PROFILE[player].BUTTONPRIM[button] == VK_WHEELUP || PROFILE[player].BUTTONPRIM[button] == VK_WHEELDOWN || PROFILE[player].BUTTONPRIM[button] == VK_WHEELLEFT || PROFILE[player].BUTTONPRIM[button] == VK_WHEELRIGHT)
|
||||
DEVICE[player].BUTTONPRIM[button] = 0;
|
||||
if(PROFILE[player].BUTTONSEC[button] == VK_WHEELUP || PROFILE[player].BUTTONSEC[button] == VK_WHEELDOWN || PROFILE[player].BUTTONSEC[button] == VK_WHEELLEFT || PROFILE[player].BUTTONSEC[button] == VK_WHEELRIGHT)
|
||||
DEVICE[player].BUTTONSEC[button] = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
DEVICE[player].WHEEL--;
|
||||
}
|
||||
while(ManyMouse_PollEvent(&event))
|
||||
{
|
||||
for(int player = PLAYER1; player < ALLPLAYERS; player++)
|
||||
{
|
||||
if(PROFILE[player].SETTINGS[CONFIG] == DISABLED) // don't check for disabled players
|
||||
continue;
|
||||
acceptalldevices = ONLY1PLAYERACTIVE; // do not filter devices if only one player is active
|
||||
if(PROFILE[player].SETTINGS[MOUSE] == (int)event.device || acceptalldevices) // mouse movement
|
||||
{
|
||||
if(event.type == MANYMOUSE_EVENT_RELMOTION && mousetoggle)
|
||||
{
|
||||
if(event.item == 0)
|
||||
DEVICE[player].XPOS += event.value;
|
||||
else
|
||||
DEVICE[player].YPOS += event.value;
|
||||
}
|
||||
if(event.type == MANYMOUSE_EVENT_BUTTON) // key presses
|
||||
{
|
||||
for(int button = 0; button < TOTALBUTTONS; button++)
|
||||
{
|
||||
int offset = event.item > 1 ? 2 : 1; // mouse button needs offset to sync with VK table (left click + offset = 0x01 aka VK_LBUTTON and right click + offset = 0x02 aka VK_RBUTTON)
|
||||
if(PROFILE[player].BUTTONPRIM[button] == (int)event.item + offset)
|
||||
DEVICE[player].BUTTONPRIM[button] = event.value;
|
||||
if(PROFILE[player].BUTTONSEC[button] == (int)event.item + offset)
|
||||
DEVICE[player].BUTTONSEC[button] = event.value;
|
||||
}
|
||||
}
|
||||
if(event.type == MANYMOUSE_EVENT_SCROLL) // mouse wheel
|
||||
{
|
||||
for(int button = 0; button < TOTALBUTTONS; button++)
|
||||
{
|
||||
if(event.item == 0) // if VK_WHEELUP/VK_WHEELDOWN
|
||||
{
|
||||
if(event.value > 0 && PROFILE[player].BUTTONPRIM[button] == VK_WHEELUP || event.value < 0 && PROFILE[player].BUTTONPRIM[button] == VK_WHEELDOWN)
|
||||
DEVICE[player].BUTTONPRIM[button] = event.value != 0;
|
||||
if(event.value > 0 && PROFILE[player].BUTTONSEC[button] == VK_WHEELUP || event.value < 0 && PROFILE[player].BUTTONSEC[button] == VK_WHEELDOWN)
|
||||
DEVICE[player].BUTTONSEC[button] = event.value != 0;
|
||||
}
|
||||
else // if VK_WHEELRIGHT/VK_WHEELLEFT
|
||||
{
|
||||
if(event.value > 0 && PROFILE[player].BUTTONPRIM[button] == VK_WHEELLEFT || event.value < 0 && PROFILE[player].BUTTONPRIM[button] == VK_WHEELRIGHT)
|
||||
DEVICE[player].BUTTONPRIM[button] = event.value != 0;
|
||||
if(event.value > 0 && PROFILE[player].BUTTONSEC[button] == VK_WHEELLEFT || event.value < 0 && PROFILE[player].BUTTONSEC[button] == VK_WHEELRIGHT)
|
||||
DEVICE[player].BUTTONSEC[button] = event.value != 0;
|
||||
}
|
||||
}
|
||||
DEVICE[player].WHEEL = 16; // hold button down for 32ms/64ms (non-oc emu need longer buffer because they run at lower framerate)
|
||||
}
|
||||
}
|
||||
if(event.type == MANYMOUSE_EVENT_KEYBOARD && (PROFILE[player].SETTINGS[KEYBOARD] == (int)event.device || acceptalldevices))
|
||||
{
|
||||
for(int button = 0; button < TOTALBUTTONS; button++) // check for key presses
|
||||
{
|
||||
if(PROFILE[player].BUTTONPRIM[button] == (int)event.item)
|
||||
DEVICE[player].BUTTONPRIM[button] = event.value;
|
||||
if(PROFILE[player].BUTTONSEC[button] == (int)event.item)
|
||||
DEVICE[player].BUTTONSEC[button] = event.value;
|
||||
}
|
||||
if(mousetogglekey == (int)event.item && event.value && !togglebuffer && windowactive) // only toggle on press and if window is active
|
||||
{
|
||||
mousetoggle = !mousetoggle;
|
||||
GetCursorPos(&lockpos);
|
||||
togglebuffer = 100 / TICKRATE; // buffer for 100ms
|
||||
if(mouselockonfocus) // if user presses mouse toggle key while lock on focus is on, increase buffer size before mouse is relocked so user can temporarily control mouse to close game/change settings
|
||||
togglebuffer *= 15;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if(checkwindowtick > (500 / TICKRATE)) // poll every 500ms
|
||||
{
|
||||
checkwindowtick = 0;
|
||||
if((mouseunlockonloss || !mousetoggle) && emulatorwindow != GetForegroundWindow()) // window is inactive
|
||||
{
|
||||
memset(&DEVICE, 0, sizeof(DEVICE)); // reset player input
|
||||
GAME_Inject(); // ship empty input to game
|
||||
windowactive = 0, mousetoggle = 0, togglebuffer = 0;
|
||||
}
|
||||
else // emu window is in focus
|
||||
{
|
||||
windowactive = 1;
|
||||
if(mouselockonfocus && !mousetoggle && !togglebuffer) // if mouselockonfocus is on and window was refocused/mouse toggle is off, turn on mouse toggle
|
||||
{
|
||||
mousetoggle = 1;
|
||||
GetCursorPos(&lockpos);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
checkwindowtick++;
|
||||
if(windowactive && GAME_Status() && !configdialogopen) // if emulator is focused, game is valid and config dialog isn't open
|
||||
GAME_Inject(); // send input to game driver
|
||||
Sleep(TICKRATE);
|
||||
}
|
||||
GAME_Quit(); // reset game driver's global variables
|
||||
return 0;
|
||||
}
|
||||
//==========================================================================
|
||||
// Purpose: Returns a single key
|
||||
//==========================================================================
|
||||
int DEV_ReturnKey(void)
|
||||
{
|
||||
int key = 0;
|
||||
ManyMouseEvent event; // hold current input event (movement, buttons, ect)
|
||||
while(ManyMouse_PollEvent(&event))
|
||||
{
|
||||
if(event.type == MANYMOUSE_EVENT_BUTTON)
|
||||
{
|
||||
if(event.item < 2)
|
||||
key = event.item ? VK_RBUTTON : VK_LBUTTON;
|
||||
else if(event.item == 2)
|
||||
key = VK_MBUTTON;
|
||||
else if(event.item == 3)
|
||||
key = VK_XBUTTON1;
|
||||
else
|
||||
key = VK_XBUTTON2;
|
||||
}
|
||||
else if(event.type == MANYMOUSE_EVENT_SCROLL)
|
||||
{
|
||||
if(event.item == 0)
|
||||
key = event.value > 0 ? VK_WHEELUP : VK_WHEELDOWN;
|
||||
else
|
||||
key = event.value > 0 ? VK_WHEELRIGHT : VK_WHEELLEFT;
|
||||
}
|
||||
else if(event.type == MANYMOUSE_EVENT_KEYBOARD)
|
||||
key = event.item;
|
||||
}
|
||||
return ClampInt(key, 0, 0xFF); // sanity check key return
|
||||
}
|
||||
//==========================================================================
|
||||
// Purpose: Returns device id of detected input
|
||||
//==========================================================================
|
||||
int DEV_ReturnDeviceID(const int devicetype)
|
||||
{
|
||||
ManyMouseEvent event; // hold current input event (movement, buttons, ect)
|
||||
while(ManyMouse_PollEvent(&event))
|
||||
if(devicetype == MOUSETYPE && (event.type == MANYMOUSE_EVENT_BUTTON || event.type == MANYMOUSE_EVENT_SCROLL) || devicetype == KEYBOARDTYPE && event.type == MANYMOUSE_EVENT_KEYBOARD)
|
||||
return event.device;
|
||||
return -1;
|
||||
}
|
||||
//==========================================================================
|
||||
// Purpose: Returns the device name given a type
|
||||
//==========================================================================
|
||||
const char *DEV_Name(const int id)
|
||||
{
|
||||
if(ManyMouse_DeviceName(id, MOUSETYPE) != NULL)
|
||||
return ManyMouse_DeviceName(id, MOUSETYPE);
|
||||
if(ManyMouse_DeviceName(id, KEYBOARDTYPE) != NULL)
|
||||
return ManyMouse_DeviceName(id, KEYBOARDTYPE);
|
||||
return NULL;
|
||||
}
|
||||
//==========================================================================
|
||||
// Purpose: Wraps ManyMouse device name and returns the device type
|
||||
//==========================================================================
|
||||
int DEV_Type(const int id)
|
||||
{
|
||||
return ManyMouse_DeviceName(id, MOUSETYPE) != NULL ? MOUSETYPE : KEYBOARDTYPE; // 0 mouse : 1 keyboard
|
||||
}
|
||||
//==========================================================================
|
||||
// Purpose: Returns the index id within a type (for converting to device combobox)
|
||||
//==========================================================================
|
||||
int DEV_TypeIndex(const int id)
|
||||
{
|
||||
int kbcount = -1, mscount = -1;
|
||||
for(int index = 0; index < DEV_Init(); index++)
|
||||
{
|
||||
if(DEV_Type(index) == MOUSETYPE)
|
||||
mscount++;
|
||||
else
|
||||
kbcount++;
|
||||
if(index == id)
|
||||
return DEV_Type(index) == MOUSETYPE ? mscount : kbcount;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
//==========================================================================
|
||||
// Purpose: Converts a type index id to its real id (for converting from device combobox)
|
||||
//==========================================================================
|
||||
int DEV_TypeID(const int id, const int devicetype)
|
||||
{
|
||||
int kbcount = -1, mscount = -1;
|
||||
for(int index = 0; index < DEV_Init(); index++)
|
||||
{
|
||||
if(DEV_Type(index) == MOUSETYPE)
|
||||
mscount++;
|
||||
else
|
||||
kbcount++;
|
||||
if(id == mscount && devicetype == MOUSETYPE || id == kbcount && devicetype == KEYBOARDTYPE)
|
||||
return index;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
//==========================================================================
|
||||
// Mouse Injector Plugin
|
||||
//==========================================================================
|
||||
// Copyright (C) 2016-2021 Carnivorous
|
||||
// All rights reserved.
|
||||
//
|
||||
// Mouse Injector 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, visit http://www.gnu.org/licenses/gpl-2.0.html
|
||||
//==========================================================================
|
||||
extern int windowactive;
|
||||
|
||||
extern int DEV_Init(void);
|
||||
extern void DEV_Quit(void);
|
||||
extern DWORD WINAPI DEV_InjectThread();
|
||||
extern int DEV_ReturnKey(void);
|
||||
extern int DEV_ReturnDeviceID(const int devicetype);
|
||||
extern const char *DEV_Name(const int id);
|
||||
extern int DEV_Type(const int id);
|
||||
extern int DEV_TypeIndex(const int id);
|
||||
extern int DEV_TypeID(const int id, const int devicetype);
|
||||
@@ -1,205 +0,0 @@
|
||||
//==========================================================================
|
||||
// Mouse Injector Plugin
|
||||
//==========================================================================
|
||||
// Copyright (C) 2016-2021 Carnivorous
|
||||
// All rights reserved.
|
||||
//
|
||||
// Mouse Injector 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, visit http://www.gnu.org/licenses/gpl-2.0.html
|
||||
//==========================================================================
|
||||
#ifdef ADD_DISCORD_PRESENCE
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include "global.h"
|
||||
#include "discord.h"
|
||||
#include "maindll.h"
|
||||
#include "games/game.h"
|
||||
#include "games/memory.h"
|
||||
#include "./discord/discord_rpc.h"
|
||||
|
||||
#define ROMCRC1 0x10
|
||||
#define ROMCRC2 0x14
|
||||
#define ROMNAME 0x28
|
||||
// GOLDENEYE ADDRESSES
|
||||
#define GE_stageid 0x8002A8F4
|
||||
#define GE_difficulty 0x8002A8FC
|
||||
#define GE_camera 0x80036494
|
||||
#define GE_pause 0x80048370
|
||||
#define GE_menupage 0x8002A8C0
|
||||
#define GE_sptime 0x80079A20
|
||||
#define GE_mptime 0x80048394
|
||||
#define GE_gamemode 0x8002A8F0
|
||||
#define GECRC1 0xDCBC50D1
|
||||
#define GECRC2 0x09FD1AA3
|
||||
// PERFECT DARK ADDRESSES
|
||||
#define PD_stageid 0x800624E4
|
||||
#define PD_difficulty 0x80084020
|
||||
#define PD_camera 0x8009A26C
|
||||
#define PD_pause 0x80084014
|
||||
#define PD_mppause 0x800ACBA6
|
||||
#define PD_joannadata 0x8009A024
|
||||
#define PD_sptime 0x801BD21C - 0x801BB6A0
|
||||
#define PD_mptime 0x80084024
|
||||
#define PDCRC1 0x41F2B98F
|
||||
#define PDCRC2 0xB458B466
|
||||
|
||||
static const char gestagenames[0x3A][0x0C] = {"", "", "", "", "", "", "", "", "", "Bunker I", "", "", "", "", "", "", "", "", "", "", "Silo", "", "Statue Park", "Control", "Archives", "Train", "Frigate", "Bunker II", "Aztec", "Streets", "Depot", "Complex", "Egypt", "Dam", "Facility", "Runway", "Surface I", "Jungle", "Temple", "Caverns", "Citadel", "Cradle", "", "Surface II", "", "Basement", "Stack", "", "Library", "", "Caves", "", "", "", "Credits", "", "", ""}; // stage names
|
||||
static const char gedifficulty[0x04][0x0D] = {"Agent", "Secret Agent", "00 Agent", "007"}; // difficulty string
|
||||
static const char pdstagenames[0x51][0x17] = {"", "", "", "", "", "", "", "", "", "Maian SOS", "", "", "", "", "", "", "", "", "", "", "", "", "WAR!", "Ravine", "", "A51 Escape", "", "", "Crash Site", "Chicago", "G5 Building", "Complex", "G5 Building", "Pelagic II", "dataDyne Extraction", "", "", "Temple", "Carrington Institute", "Air Base", "", "Pipes", "Skedar Ruins", "", "Carrington Villa", "Carrington Institute", "", "A51 Infiltration", "dataDyne Defection", "Air Force One", "Skedar", "dataDyne Investigation", "Attack Ship", "A51 Rescue", "", "Mr. Blonde's Revenge", "Deep Sea", "Base", "", "Area 52", "Warehouse", "Car Park", "", "", "", "Ruins", "Sewers", "Felicity", "Fortress", "Villa", "", "Grid", "", "", "", "", "", "", "", "Duel"}; // stage names
|
||||
static const char pddifficulty[0x03][0x0E] = {"Agent", "Secret Agent", "Perfect Agent"}; // difficulty string
|
||||
static const int pdmpstageids[0x10] = {0x32, 0x29, 0x17, 0x20, 0x42, 0x3C, 0x47, 0x41, 0x3B, 0x39, 0x44, 0x45, 0x3D, 0x25, 0x1F, 0x43}; // multiplayer stage ids
|
||||
static DiscordRichPresence presence; // presence struct for update function
|
||||
static int alreadyexec = 0; // has init already exec?
|
||||
static char thumbnailid[0x5]; // holds thumbnail id
|
||||
|
||||
static void DRP_Init(void);
|
||||
void DRP_Update(void);
|
||||
void DRP_Quit(void);
|
||||
|
||||
//==========================================================================
|
||||
// Purpose: init discord rich presence
|
||||
//==========================================================================
|
||||
static void DRP_Init(void)
|
||||
{
|
||||
Discord_Initialize("454158757262262272", NULL, 1, NULL);
|
||||
alreadyexec = 1;
|
||||
}
|
||||
//==========================================================================
|
||||
// Purpose: updates discord rich presence
|
||||
// Changed Globals: presence struct
|
||||
//==========================================================================
|
||||
void DRP_Update(void)
|
||||
{
|
||||
if(!alreadyexec)
|
||||
DRP_Init();
|
||||
memset(&presence, 0, sizeof(presence)); // set presence struct to 0
|
||||
if(GAME_Name() != NULL)
|
||||
{
|
||||
if(EMU_ReadROM(ROMCRC1) == GECRC1 && EMU_ReadROM(ROMCRC2) == GECRC2) // check if official GE rom
|
||||
{
|
||||
presence.largeImageKey = "ge"; // large default icon (not in-game)
|
||||
presence.largeImageText = "GoldenEye 007";
|
||||
if(EMU_ReadInt(GE_menupage) == 11) // if in-game
|
||||
{
|
||||
presence.smallImageKey = "geingame"; // set small icon
|
||||
presence.details = gestagenames[ClampInt(EMU_ReadInt(GE_stageid), 0x00, 0x39)]; // set details to map name (after clamping)
|
||||
int mpflag = EMU_ReadInt(GE_gamemode) == 1; // set to 1 if gamemode is multiplayer (0 = sp, 1 = mp, 2 = cheats)
|
||||
presence.state = !mpflag ? gedifficulty[ClampInt(EMU_ReadInt(GE_difficulty), 0, 3)] : "Multiplayer"; // set difficulty/multiplayer to state
|
||||
if(EMU_ReadInt(GE_pause) == 0 && (EMU_ReadInt(GE_camera) == 4 || EMU_ReadInt(GE_camera) == 0)) // if in gameplay mode (not intro swirl) and not paused, calculate time
|
||||
{
|
||||
time_t currenttime = time(NULL); // get current time from OS
|
||||
presence.startTimestamp = currenttime - (EMU_ReadInt(!mpflag ? GE_sptime : GE_mptime) / 60); // convert in-game time (60 Hz) to seconds and subtract from current time to get starting time for current map
|
||||
}
|
||||
sprintf(thumbnailid, "ge%1.2x", EMU_ReadInt(GE_stageid)); // set thumbnail id
|
||||
presence.largeImageKey = thumbnailid;
|
||||
}
|
||||
else // not in-game
|
||||
{
|
||||
if(EMU_ReadInt(GE_menupage) >= -1 && EMU_ReadInt(GE_menupage) <= 4) // intro range
|
||||
presence.details = "Intro";
|
||||
else if(EMU_ReadInt(GE_menupage) == 24) // character credits
|
||||
presence.details = "Credits";
|
||||
else // in menu
|
||||
presence.details = "In Main Menu";
|
||||
}
|
||||
}
|
||||
else if(EMU_ReadROM(ROMCRC1) == PDCRC1 && EMU_ReadROM(ROMCRC2) == PDCRC2) // check if official PD rom
|
||||
{
|
||||
presence.largeImageKey = "pd"; // large default icon (not in-game)
|
||||
presence.largeImageText = "Perfect Dark";
|
||||
if(EMU_ReadInt(PD_stageid) >= 0x09 && EMU_ReadInt(PD_stageid) < 0x51) // if stage id is within char array
|
||||
{
|
||||
presence.smallImageKey = "pdingame"; // set small icon
|
||||
presence.details = pdstagenames[EMU_ReadInt(PD_stageid)]; // set details to map name
|
||||
if(EMU_ReadInt(PD_stageid) != 0x26) // if level isn't carrington institute
|
||||
{
|
||||
int mpflag = 0;
|
||||
for(int index = 0; index < 0x10; index++) // compare current stage id to list of mp stage ids
|
||||
if(pdmpstageids[index] == EMU_ReadInt(PD_stageid))
|
||||
mpflag = 1;
|
||||
presence.state = !mpflag ? pddifficulty[ClampInt(EMU_ReadInt(PD_difficulty), 0, 2)] : "Combat Simulator"; // set difficulty/combat simulator to state
|
||||
if(EMU_ReadInt(PD_pause) == 0 && (EMU_ReadShort(PD_mppause) & 0xFF00) == 0 && (EMU_ReadInt(PD_camera) == 1 || EMU_ReadInt(PD_camera) == 7)) // if in gameplay mode (not cutscene) and not paused, calculate time
|
||||
{
|
||||
time_t currenttime = time(NULL); // get current time from OS
|
||||
int gametime;
|
||||
if(!mpflag)
|
||||
gametime = EMU_ReadInt(EMU_ReadInt(PD_joannadata) + PD_sptime) / 60; // convert in-game SP time (60 Hz) to seconds (SP time is part of player struct)
|
||||
else
|
||||
gametime = EMU_ReadInt(PD_mptime) / 60; // convert in-game MP time (60 Hz) to seconds
|
||||
presence.startTimestamp = currenttime - gametime; // subtract from current time to get starting time for current map
|
||||
}
|
||||
}
|
||||
sprintf(thumbnailid, "pd%1.2x", EMU_ReadInt(PD_stageid)); // set thumbnail id
|
||||
presence.largeImageKey = thumbnailid;
|
||||
}
|
||||
else if(EMU_ReadInt(PD_stageid) == -1)
|
||||
presence.details = "Intro";
|
||||
else if(EMU_ReadInt(PD_stageid) == 0x5C) // if credits
|
||||
presence.state = "Credits";
|
||||
}
|
||||
else // user is running a rom hack
|
||||
{
|
||||
switch(EMU_ReadROM(ROMNAME))
|
||||
{
|
||||
case 0x45522020: // if GF rom hack
|
||||
presence.largeImageKey = "gfcustom";
|
||||
presence.largeImageText = "Goldfinger 64";
|
||||
break;
|
||||
case 0x65205820: // if GEX rom hack
|
||||
presence.largeImageKey = "gexcustom";
|
||||
presence.largeImageText = "GoldenEye X";
|
||||
break;
|
||||
case 0x45202020: // if GE rom hack
|
||||
presence.largeImageKey = "custom";
|
||||
presence.largeImageText = "GoldenEye 007 (ROM Hack)";
|
||||
break;
|
||||
default: // assume PD rom hack
|
||||
presence.largeImageKey = "pdcustom";
|
||||
presence.largeImageText = "Perfect Dark (ROM Hack)";
|
||||
break;
|
||||
}
|
||||
presence.details = presence.largeImageText;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
presence.largeImageKey = "logo"; // default 1964 icon
|
||||
presence.largeImageText = "N64 Emulator for GE/PD";
|
||||
presence.details = "Not In-Game";
|
||||
}
|
||||
Discord_UpdatePresence(&presence);
|
||||
}
|
||||
//==========================================================================
|
||||
// Purpose: safely shutdown discord rich presence
|
||||
// Changed Globals: alreadyexec
|
||||
//==========================================================================
|
||||
void DRP_Quit(void)
|
||||
{
|
||||
Discord_ClearPresence();
|
||||
Discord_Shutdown();
|
||||
alreadyexec = 0;
|
||||
}
|
||||
#else
|
||||
//==========================================================================
|
||||
// Purpose: dummy functions for non-drp build
|
||||
//==========================================================================
|
||||
void DRP_Update(void)
|
||||
{
|
||||
return;
|
||||
}
|
||||
void DRP_Quit(void)
|
||||
{
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
@@ -1,21 +0,0 @@
|
||||
//==========================================================================
|
||||
// Mouse Injector Plugin
|
||||
//==========================================================================
|
||||
// Copyright (C) 2016-2021 Carnivorous
|
||||
// All rights reserved.
|
||||
//
|
||||
// Mouse Injector 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, visit http://www.gnu.org/licenses/gpl-2.0.html
|
||||
//==========================================================================
|
||||
extern void DRP_Update(void);
|
||||
extern void DRP_Quit(void);
|
||||
Binary file not shown.
@@ -1,26 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#if defined(DISCORD_DYNAMIC_LIB)
|
||||
# if defined(_WIN32)
|
||||
# if defined(DISCORD_BUILDING_SDK)
|
||||
# define DISCORD_EXPORT __declspec(dllexport)
|
||||
# else
|
||||
# define DISCORD_EXPORT __declspec(dllimport)
|
||||
# endif
|
||||
# else
|
||||
# define DISCORD_EXPORT __attribute__((visibility("default")))
|
||||
# endif
|
||||
#else
|
||||
# define DISCORD_EXPORT
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
DISCORD_EXPORT void Discord_Register(const char* applicationId, const char* command);
|
||||
DISCORD_EXPORT void Discord_RegisterSteamGame(const char* applicationId, const char* steamId);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -1,87 +0,0 @@
|
||||
#pragma once
|
||||
#include <stdint.h>
|
||||
|
||||
// clang-format off
|
||||
|
||||
#if defined(DISCORD_DYNAMIC_LIB)
|
||||
# if defined(_WIN32)
|
||||
# if defined(DISCORD_BUILDING_SDK)
|
||||
# define DISCORD_EXPORT __declspec(dllexport)
|
||||
# else
|
||||
# define DISCORD_EXPORT __declspec(dllimport)
|
||||
# endif
|
||||
# else
|
||||
# define DISCORD_EXPORT __attribute__((visibility("default")))
|
||||
# endif
|
||||
#else
|
||||
# define DISCORD_EXPORT
|
||||
#endif
|
||||
|
||||
// clang-format on
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct DiscordRichPresence {
|
||||
const char* state; /* max 128 bytes */
|
||||
const char* details; /* max 128 bytes */
|
||||
int64_t startTimestamp;
|
||||
int64_t endTimestamp;
|
||||
const char* largeImageKey; /* max 32 bytes */
|
||||
const char* largeImageText; /* max 128 bytes */
|
||||
const char* smallImageKey; /* max 32 bytes */
|
||||
const char* smallImageText; /* max 128 bytes */
|
||||
const char* partyId; /* max 128 bytes */
|
||||
int partySize;
|
||||
int partyMax;
|
||||
const char* matchSecret; /* max 128 bytes */
|
||||
const char* joinSecret; /* max 128 bytes */
|
||||
const char* spectateSecret; /* max 128 bytes */
|
||||
int8_t instance;
|
||||
} DiscordRichPresence;
|
||||
|
||||
typedef struct DiscordUser {
|
||||
const char* userId;
|
||||
const char* username;
|
||||
const char* discriminator;
|
||||
const char* avatar;
|
||||
} DiscordUser;
|
||||
|
||||
typedef struct DiscordEventHandlers {
|
||||
void (*ready)(const DiscordUser* request);
|
||||
void (*disconnected)(int errorCode, const char* message);
|
||||
void (*errored)(int errorCode, const char* message);
|
||||
void (*joinGame)(const char* joinSecret);
|
||||
void (*spectateGame)(const char* spectateSecret);
|
||||
void (*joinRequest)(const DiscordUser* request);
|
||||
} DiscordEventHandlers;
|
||||
|
||||
#define DISCORD_REPLY_NO 0
|
||||
#define DISCORD_REPLY_YES 1
|
||||
#define DISCORD_REPLY_IGNORE 2
|
||||
|
||||
DISCORD_EXPORT void Discord_Initialize(const char* applicationId,
|
||||
DiscordEventHandlers* handlers,
|
||||
int autoRegister,
|
||||
const char* optionalSteamId);
|
||||
DISCORD_EXPORT void Discord_Shutdown(void);
|
||||
|
||||
/* checks for incoming messages, dispatches callbacks */
|
||||
DISCORD_EXPORT void Discord_RunCallbacks(void);
|
||||
|
||||
/* If you disable the lib starting its own io thread, you'll need to call this from your own */
|
||||
#ifdef DISCORD_DISABLE_IO_THREAD
|
||||
DISCORD_EXPORT void Discord_UpdateConnection(void);
|
||||
#endif
|
||||
|
||||
DISCORD_EXPORT void Discord_UpdatePresence(const DiscordRichPresence* presence);
|
||||
DISCORD_EXPORT void Discord_ClearPresence(void);
|
||||
|
||||
DISCORD_EXPORT void Discord_Respond(const char* userid, /* DISCORD_REPLY_ */ int reply);
|
||||
|
||||
DISCORD_EXPORT void Discord_UpdateHandlers(DiscordEventHandlers* handlers);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
@@ -1,85 +0,0 @@
|
||||
//==========================================================================
|
||||
// Mouse Injector Plugin
|
||||
//==========================================================================
|
||||
// Copyright (C) 2016-2021 Carnivorous
|
||||
// All rights reserved.
|
||||
//
|
||||
// Mouse Injector 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, visit http://www.gnu.org/licenses/gpl-2.0.html
|
||||
//==========================================================================
|
||||
#include <stdlib.h>
|
||||
#include "game.h"
|
||||
|
||||
extern const GAMEDRIVER *GAME_GOLDENEYE007;
|
||||
extern const GAMEDRIVER *GAME_PERFECTDARK;
|
||||
|
||||
static const GAMEDRIVER **GAMELIST[] =
|
||||
{
|
||||
&GAME_GOLDENEYE007,
|
||||
&GAME_PERFECTDARK
|
||||
};
|
||||
|
||||
static const GAMEDRIVER *CURRENT_GAME = NULL;
|
||||
static const int upper = (sizeof(GAMELIST) / sizeof(GAMELIST[0]));
|
||||
|
||||
int GAME_Status(void);
|
||||
const char *GAME_Name(void);
|
||||
void GAME_Inject(void);
|
||||
void GAME_Quit(void);
|
||||
|
||||
//==========================================================================
|
||||
// Purpose: check all game interfaces for game
|
||||
//==========================================================================
|
||||
int GAME_Status(void)
|
||||
{
|
||||
if(CURRENT_GAME != NULL) // if any game has been detected previously
|
||||
{
|
||||
if(CURRENT_GAME->Status()) // check if game is still active, else check every supported driver
|
||||
return 1;
|
||||
CURRENT_GAME = NULL;
|
||||
}
|
||||
const GAMEDRIVER *THIS_GAME;
|
||||
for(int i = 0; (i < upper) && (CURRENT_GAME == NULL); i++)
|
||||
{
|
||||
THIS_GAME = *(GAMELIST[i]);
|
||||
if(THIS_GAME != NULL && THIS_GAME->Status())
|
||||
CURRENT_GAME = THIS_GAME;
|
||||
}
|
||||
return (CURRENT_GAME != NULL);
|
||||
}
|
||||
//==========================================================================
|
||||
// Purpose: return game driver name
|
||||
//==========================================================================
|
||||
const char *GAME_Name(void)
|
||||
{
|
||||
if(CURRENT_GAME != NULL)
|
||||
return CURRENT_GAME->Name;
|
||||
return NULL;
|
||||
}
|
||||
//==========================================================================
|
||||
// Purpose: inject via game driver
|
||||
//==========================================================================
|
||||
void GAME_Inject(void)
|
||||
{
|
||||
if(CURRENT_GAME != NULL)
|
||||
CURRENT_GAME->Inject();
|
||||
}
|
||||
//==========================================================================
|
||||
// Purpose: quit game driver
|
||||
//==========================================================================
|
||||
void GAME_Quit(void)
|
||||
{
|
||||
if(CURRENT_GAME != NULL)
|
||||
CURRENT_GAME->Quit();
|
||||
CURRENT_GAME = NULL;
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
//==========================================================================
|
||||
// Mouse Injector Plugin
|
||||
//==========================================================================
|
||||
// Copyright (C) 2016-2021 Carnivorous
|
||||
// All rights reserved.
|
||||
//
|
||||
// Mouse Injector 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, visit http://www.gnu.org/licenses/gpl-2.0.html
|
||||
//==========================================================================
|
||||
typedef struct
|
||||
{
|
||||
const char *Name;
|
||||
int (*Status)(void);
|
||||
void (*Inject)(void);
|
||||
void (*Quit)(void);
|
||||
} GAMEDRIVER;
|
||||
|
||||
extern int GAME_Status(void);
|
||||
extern const char *GAME_Name(void);
|
||||
extern void GAME_Inject(void);
|
||||
extern void GAME_Quit(void);
|
||||
@@ -1,383 +0,0 @@
|
||||
//==========================================================================
|
||||
// Mouse Injector Plugin
|
||||
//==========================================================================
|
||||
// Copyright (C) 2016-2021 Carnivorous
|
||||
// All rights reserved.
|
||||
//
|
||||
// Mouse Injector 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, visit http://www.gnu.org/licenses/gpl-2.0.html
|
||||
//==========================================================================
|
||||
#include <math.h>
|
||||
#include "../global.h"
|
||||
#include "../maindll.h"
|
||||
#include "game.h"
|
||||
#include "memory.h"
|
||||
|
||||
#define GUNAIMLIMIT 6.879164696 // 0x40DC221E
|
||||
#define CROSSHAIRLIMIT 5.159373283 // 0x40A51996
|
||||
#define TANKXROTATIONLIMIT 6.283185005 // 0x40C90FDA
|
||||
#define PI 3.1415927 // 0x40490FDB
|
||||
// GOLDENEYE ADDRESSES - OFFSET ADDRESSES BELOW (REQUIRES PLAYERBASE TO USE)
|
||||
#define GE_stanceflag 0x800D2FFC - 0x800D2F60
|
||||
#define GE_deathflag 0x800D3038 - 0x800D2F60
|
||||
#define GE_camx 0x800D30A8 - 0x800D2F60
|
||||
#define GE_camy 0x800D30B8 - 0x800D2F60
|
||||
#define GE_fov 0x800D4124 - 0x800D2F60
|
||||
#define GE_crosshairx 0x800D3F50 - 0x800D2F60
|
||||
#define GE_crosshairy 0x800D3F54 - 0x800D2F60
|
||||
#define GE_watch 0x800D3128 - 0x800D2F60
|
||||
#define GE_gunx 0x800D3F64 - 0x800D2F60
|
||||
#define GE_guny 0x800D3F68 - 0x800D2F60
|
||||
#define GE_aimingflag 0x800D3084 - 0x800D2F60
|
||||
#define GE_currentweapon 0x800D37D0 - 0x800D2F60
|
||||
#define GE_multipausemenu 0x800A9D24 - 0x800A7360
|
||||
// STATIC ADDRESSES BELOW
|
||||
#define BONDDATA(X) (unsigned int)EMU_ReadInt(0x80079EE0 + (X * 0x4)) // player pointer address (0x4 offset for each players)
|
||||
#define GE_camera 0x80036494 // camera flag (0 = multiplayer, 1 = map overview, 2 = start flyby, 3 = in flyby, 4 = player in control, 5 = trigger restart map)
|
||||
#define GE_exit 0x800364B0 // exit flag (0 = disable controls, 1 = enable controls)
|
||||
#define GE_pause 0x80048370 // pause flag (1 = GE is paused)
|
||||
#define GE_menupage 0x8002A8C0 // menu page id
|
||||
#define GE_menux 0x8002A908 // crosshair menu cursor x axis
|
||||
#define GE_menuy 0x8002A90C // crosshair menu cursor y axis
|
||||
#define GE_tankxrot 0x80036484 // tank x rotation
|
||||
#define GE_tankflag 0x80036448 // tank flag (0 = walking, 1 = in-tank)
|
||||
#define GE_matchended 0x8008C700 // multiplayer match flag
|
||||
#define GE_defaultratio 0x80055264 // 16:9 ratio default
|
||||
#define GE_defaultratiocrosshair 0x0009F198 // 16:9 crosshair ratio default (rom)
|
||||
#define GE_defaultfov 0x000B78BC // field of view default (rom)
|
||||
#define GE_defaultfovinit 0x000CF838 // field of view init value (rom)
|
||||
#define GE_defaultfovzoom 0x000B78DC // field of view default for zoom (rom)
|
||||
#define GE_defaultzoomspeed 0x8004F1A8 // default zoom speed
|
||||
#define GE_showcrosshair 0x0009F128 // show crosshair code (rom)
|
||||
#define GE_crosshairimage 0x0029DE8C // crosshair image (rom)
|
||||
#define GE_introcounter 0x8002A8CC // counter for intro
|
||||
#define GE_seenintroflag 0x8002A930 // seen intro flag
|
||||
#define GE_controlstyle 0x000D98FC // instruction reads the current controller style (rom)
|
||||
#define GE_reversepitch 0x000D9970 // instruction reads the current reverse pitch option (rom)
|
||||
#define GE_pickupyaxisthreshold 0x800532E0 // y axis threshold on picking up weapons
|
||||
#define GE_weaponypos 0x8003249C // y axis position for view models
|
||||
#define GE_weaponzpos (GE_weaponypos + 4) // z axis position for view models
|
||||
|
||||
static unsigned int playerbase[4] = {0}; // current player's bonddata address
|
||||
static int safetocrouch[4] = {1, 1, 1, 1}, safetostand[4] = {0}, crouchstance[4] = {0}; // used for crouch toggle (limits tick-tocking)
|
||||
static float crosshairposx[4], crosshairposy[4], aimx[4], aimy[4];
|
||||
|
||||
int GE_Status(void);
|
||||
void GE_Inject(void);
|
||||
static void GE_Crouch(const int player);
|
||||
#define GE_ResetCrouchToggle(X) safetocrouch[X] = 1, safetostand[X] = 0, crouchstance[X] = 0 // reset crouch toggle bind
|
||||
static void GE_AimMode(const int player, const int aimingflag, const float fov, const float basefov);
|
||||
static void GE_Controller(void);
|
||||
static void GE_InjectHacks(void);
|
||||
void GE_Quit(void);
|
||||
|
||||
static const GAMEDRIVER GAMEDRIVER_INTERFACE =
|
||||
{
|
||||
"GoldenEye 007",
|
||||
GE_Status,
|
||||
GE_Inject,
|
||||
GE_Quit
|
||||
};
|
||||
|
||||
const GAMEDRIVER *GAME_GOLDENEYE007 = &GAMEDRIVER_INTERFACE;
|
||||
|
||||
//==========================================================================
|
||||
// Purpose: returns a value, which is then used to check what game is running in game.c
|
||||
// Q: What is happening here?
|
||||
// A: We look up some static addresses and if the values are within the expected ranges the program can assume that the game is currently running
|
||||
//==========================================================================
|
||||
int GE_Status(void)
|
||||
{
|
||||
const int ge_camera = EMU_ReadInt(GE_camera), ge_page = EMU_ReadInt(GE_menupage), ge_pause = EMU_ReadInt(GE_pause), ge_exit = EMU_ReadInt(GE_exit);
|
||||
const float ge_crosshairx = EMU_ReadFloat(GE_menux), ge_crosshairy = EMU_ReadFloat(GE_menuy);
|
||||
return (ge_camera >= 0 && ge_camera <= 10 && ge_page >= -1 && ge_page <= 25 && ge_pause >= 0 && ge_pause <= 1 && ge_exit >= 0 && ge_exit <= 1 && ge_crosshairx >= 20 && ge_crosshairx <= 420 && ge_crosshairy >= 20 && ge_crosshairy <= 310); // if GoldenEye 007 is current game
|
||||
}
|
||||
//==========================================================================
|
||||
// Purpose: calculate mouse movement and inject into current game
|
||||
// Changes Globals: safetocrouch, safetostand, crouchstance
|
||||
// Q: Could you explain !aimingflag ? 10.0f : 40.0f
|
||||
// A: While the player is aiming weapon sway will be reduced by 75%. While this is not in the original design of GE/PD I feel it gives a legitimate advantage for aiming instead of only making the crosshair visible
|
||||
// Q: Could you explain basefov = fov > 60.0f ? (float)OVERRIDEFOV : 60.0f
|
||||
// A: For weapons that zoom, the fov is lower than 60 - when this happens we compute our calculations using 60 as a base instead of the override fov. This is to prevent weapons from becoming too sluggish to move while zoomed with a high override fov
|
||||
// Q: Could you explain if(aimingflag) gunx /= emuoverclock ? 1.03f : 1.07f, crosshairx /= emuoverclock ? 1.03f : 1.07f;
|
||||
// A: GE_InjectHacks() disables the engine from overwriting the crosshair pos and gun rot - this is so aiming is jitter free. But it removed the auto centering code while aiming. If the player turns off cursor aiming for GE, the crosshair and gun will no longer move back to the center (it'll float to the corners of the screen). This if statement will emulate the centering code. The emuoverclock condition will make the scale the same - regardless of overclock or stock (inject exec at higher tickrate if overclocked).
|
||||
//==========================================================================
|
||||
void GE_Inject(void)
|
||||
{
|
||||
if(EMU_ReadInt(GE_menupage) < 1) // hacks can only be injected at boot sequence before code blocks are cached, so inject until the main menu
|
||||
GE_InjectHacks();
|
||||
const int camera = EMU_ReadInt(GE_camera);
|
||||
const int exit = EMU_ReadInt(GE_exit);
|
||||
const int pause = EMU_ReadInt(GE_pause);
|
||||
const int menupage = EMU_ReadInt(GE_menupage);
|
||||
const int tankflag = EMU_ReadInt(GE_tankflag);
|
||||
const int mproundend = EMU_ReadInt(GE_matchended);
|
||||
for(int player = PLAYER1; player < ALLPLAYERS; player++)
|
||||
{
|
||||
if(PROFILE[player].SETTINGS[CONFIG] == DISABLED) // bypass disabled players
|
||||
continue;
|
||||
playerbase[player] = BONDDATA(player);
|
||||
const int dead = EMU_ReadInt(playerbase[player] + GE_deathflag);
|
||||
const int watch = EMU_ReadInt(playerbase[player] + GE_watch);
|
||||
const int aimingflag = EMU_ReadInt(playerbase[player] + GE_aimingflag);
|
||||
const int mppausemenu = EMU_ReadInt(playerbase[player] + GE_multipausemenu);
|
||||
const int cursoraimingflag = PROFILE[player].SETTINGS[GEAIMMODE] && aimingflag;
|
||||
const float fov = EMU_ReadFloat(playerbase[player] + GE_fov);
|
||||
const float basefov = fov > 60.0f ? (float)OVERRIDEFOV : 60.0f;
|
||||
const float mouseaccel = PROFILE[player].SETTINGS[ACCELERATION] ? sqrt(DEVICE[player].XPOS * DEVICE[player].XPOS + DEVICE[player].YPOS * DEVICE[player].YPOS) / TICKRATE / 12.0f * PROFILE[player].SETTINGS[ACCELERATION] : 0;
|
||||
const float sensitivity = PROFILE[player].SETTINGS[SENSITIVITY] / 40.0f * fmax(mouseaccel, 1);
|
||||
const float gunsensitivity = sensitivity * (PROFILE[player].SETTINGS[CROSSHAIR] / 2.5f);
|
||||
float camx = EMU_ReadFloat(playerbase[player] + GE_camx), camy = EMU_ReadFloat(playerbase[player] + GE_camy);
|
||||
if(camx >= 0 && camx <= 360 && camy >= -90 && camy <= 90 && fov >= 1 && fov <= FOV_MAX && dead == 0 && watch == 0 && pause == 0 && (camera == 4 || camera == 0) && exit == 1 && menupage == 11 && !mproundend && !mppausemenu) // if safe to inject
|
||||
{
|
||||
GE_AimMode(player, cursoraimingflag, fov, basefov);
|
||||
if(!tankflag) // player is on foot
|
||||
{
|
||||
GE_Crouch(player); // only allow crouching if player is not in tank
|
||||
if(!cursoraimingflag) // if not aiming (or geaimmode is off)
|
||||
camx += DEVICE[player].XPOS / 10.0f * sensitivity * (fov / basefov); // regular mouselook calculation
|
||||
else
|
||||
camx += aimx[player] * (fov / basefov); // scroll screen with aimx/aimy
|
||||
while(camx < 0)
|
||||
camx += 360;
|
||||
while(camx >= 360)
|
||||
camx -= 360;
|
||||
EMU_WriteFloat(playerbase[player] + GE_camx, camx);
|
||||
}
|
||||
else // player is in tank
|
||||
{
|
||||
GE_ResetCrouchToggle(player); // reset crouch toggle if in tank
|
||||
float tankx = EMU_ReadFloat(GE_tankxrot);
|
||||
if(!cursoraimingflag || EMU_ReadInt(playerbase[player] + GE_currentweapon) == 32) // if not aiming (or geaimmode is off) or player is driving tank with tank equipped as weapon, then use regular mouselook calculation
|
||||
tankx += DEVICE[player].XPOS / 10.0f * sensitivity / (360 / TANKXROTATIONLIMIT * 2.5) * (fov / basefov);
|
||||
else
|
||||
tankx += aimx[player] / (360 / TANKXROTATIONLIMIT * 2.5) * (fov / basefov);
|
||||
while(tankx < 0)
|
||||
tankx += TANKXROTATIONLIMIT;
|
||||
while(tankx >= TANKXROTATIONLIMIT)
|
||||
tankx -= TANKXROTATIONLIMIT;
|
||||
EMU_WriteFloat(GE_tankxrot, tankx);
|
||||
}
|
||||
if(!cursoraimingflag)
|
||||
camy += (!PROFILE[player].SETTINGS[INVERTPITCH] ? -DEVICE[player].YPOS : DEVICE[player].YPOS) / 10.0f * sensitivity * (fov / basefov);
|
||||
else
|
||||
camy += -aimy[player] * (fov / basefov);
|
||||
camy = ClampFloat(camy, tankflag ? -20 : -90, 90); // tank limits player from looking down -20
|
||||
EMU_WriteFloat(playerbase[player] + GE_camy, camy);
|
||||
if(PROFILE[player].SETTINGS[CROSSHAIR] && !cursoraimingflag) // if crosshair movement is enabled and player isn't aiming (don't calculate weapon movement while the player is in aim mode)
|
||||
{
|
||||
if(!tankflag)
|
||||
{
|
||||
float gunx = EMU_ReadFloat(playerbase[player] + GE_gunx), crosshairx = EMU_ReadFloat(playerbase[player] + GE_crosshairx); // after camera x and y have been calculated and injected, calculate the gun/crosshair movement
|
||||
gunx += DEVICE[player].XPOS / (!aimingflag ? 10.0f : 40.0f) * gunsensitivity * (fov / basefov) * 0.019f;
|
||||
crosshairx += DEVICE[player].XPOS / (!aimingflag ? 10.0f : 40.0f) * gunsensitivity * (fov / 4 / (basefov / 4)) * 0.01912f / RATIOFACTOR;
|
||||
if(aimingflag) // emulate cursor moving back to the center
|
||||
gunx /= emuoverclock ? 1.03f : 1.07f, crosshairx /= emuoverclock ? 1.03f : 1.07f;
|
||||
gunx = ClampFloat(gunx, -GUNAIMLIMIT, GUNAIMLIMIT);
|
||||
crosshairx = ClampFloat(crosshairx, -CROSSHAIRLIMIT, CROSSHAIRLIMIT);
|
||||
EMU_WriteFloat(playerbase[player] + GE_gunx, gunx);
|
||||
EMU_WriteFloat(playerbase[player] + GE_crosshairx, crosshairx);
|
||||
}
|
||||
if((!tankflag && camy > -90 || tankflag && camy > -20) && camy < 90) // only allow player's gun to pitch within a valid range
|
||||
{
|
||||
float guny = EMU_ReadFloat(playerbase[player] + GE_guny), crosshairy = EMU_ReadFloat(playerbase[player] + GE_crosshairy);
|
||||
guny += (!PROFILE[player].SETTINGS[INVERTPITCH] ? DEVICE[player].YPOS : -DEVICE[player].YPOS) / (!aimingflag ? 40.0f : 20.0f) * gunsensitivity * (fov / basefov) * 0.025f;
|
||||
crosshairy += (!PROFILE[player].SETTINGS[INVERTPITCH] ? DEVICE[player].YPOS : -DEVICE[player].YPOS) / (!aimingflag ? 40.0f : 20.0f) * gunsensitivity * (fov / 4 / (basefov / 4)) * 0.0225f;
|
||||
if(aimingflag)
|
||||
guny /= emuoverclock ? 1.15f : 1.35f, crosshairy /= emuoverclock ? 1.15f : 1.35f;
|
||||
guny = ClampFloat(guny, -GUNAIMLIMIT, GUNAIMLIMIT);
|
||||
crosshairy = ClampFloat(crosshairy, -CROSSHAIRLIMIT, CROSSHAIRLIMIT);
|
||||
EMU_WriteFloat(playerbase[player] + GE_guny, guny);
|
||||
EMU_WriteFloat(playerbase[player] + GE_crosshairy, crosshairy);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(player == PLAYER1 && menupage != 11 && menupage != 23) // if user is in menu (only player 1 can control menu)
|
||||
{
|
||||
float menucrosshairx = EMU_ReadFloat(GE_menux), menucrosshairy = EMU_ReadFloat(GE_menuy);
|
||||
menucrosshairx += DEVICE[player].XPOS / 10.0f * sensitivity * 6;
|
||||
menucrosshairy += DEVICE[player].YPOS / 10.0f * sensitivity * (400.0f / 290.0f * 6); // y is a little weaker then x in the menu so add more power to make it feel even with x axis
|
||||
menucrosshairx = ClampFloat(menucrosshairx, 20, 420);
|
||||
menucrosshairy = ClampFloat(menucrosshairy, 20, 310);
|
||||
EMU_WriteFloat(GE_menux, menucrosshairx);
|
||||
EMU_WriteFloat(GE_menuy, menucrosshairy);
|
||||
}
|
||||
if(dead || menupage != 11) // if player is dead or in menu, reset crouch toggle
|
||||
GE_ResetCrouchToggle(player);
|
||||
}
|
||||
GE_Controller(); // set controller data
|
||||
}
|
||||
//==========================================================================
|
||||
// Purpose: crouching function for GoldenEye (2 = stand, 1 = kneel (in tank), 0 = crouch)
|
||||
// Changes Globals: safetocrouch, crouchstance, safetostand
|
||||
//==========================================================================
|
||||
static void GE_Crouch(const int player)
|
||||
{
|
||||
int crouchheld = DEVICE[player].BUTTONPRIM[CROUCH] || DEVICE[player].BUTTONSEC[CROUCH] || DEVICE[player].BUTTONPRIM[KNEEL] || DEVICE[player].BUTTONSEC[KNEEL];
|
||||
if(PROFILE[player].SETTINGS[CROUCHTOGGLE]) // check and toggle player stance
|
||||
{
|
||||
if(safetocrouch[player] && crouchheld) // standing to crouching
|
||||
safetocrouch[player] = 0, crouchstance[player] = 1;
|
||||
else if(!safetocrouch[player] && !crouchheld) // crouch is no longer being held, ready to stand
|
||||
safetostand[player] = 1;
|
||||
if(safetostand[player] && crouchheld) // stand up
|
||||
safetocrouch[player] = 1, crouchstance[player] = 0;
|
||||
else if(safetostand[player] && safetocrouch[player] && !crouchheld) // crouch key not active, ready to toggle
|
||||
safetostand[player] = 0;
|
||||
crouchheld = crouchstance[player];
|
||||
}
|
||||
EMU_WriteInt(playerbase[player] + GE_stanceflag, !crouchheld ? 2 : 0); // set in-game stance
|
||||
}
|
||||
//==========================================================================
|
||||
// Purpose: replicate the original aiming system, uses aimx/y to move screen when crosshair is on border of screen
|
||||
// Changes Globals: crosshairposx, crosshairposy, aimx, aimy
|
||||
//==========================================================================
|
||||
static void GE_AimMode(const int player, const int aimingflag, const float fov, const float basefov)
|
||||
{
|
||||
const float crosshairx = EMU_ReadFloat(playerbase[player] + GE_crosshairx), crosshairy = EMU_ReadFloat(playerbase[player] + GE_crosshairy), offsetpos[2][33] = {{0, 0, 0, 0, 0.1625, 0.1625, 0.15, 0.5, 0.8, 0.4, 0.5, 0.5, 0.48, 0.9, 0.25, 0.6, 0.6, 0.7, 0.25, 0.15, 0.1625, 0.1625, 0.5, 0.5, 0.9, 0.9, 0, 0, 0, 0, 0, 0.4}, {0, 0, 0, 0, 0.1, 0.1, 0.2, 0.325, 1, 0.3, 0.425, 0.425, 0.45, 0.95, 0.1, 0.55, 0.5, 0.7, 0.25, 0.1, 0.1, 0.1, 0.275, 1, 0.9, 0.8, 0, 0, 0, 0, 0, 0.25}}; // table of X/Y offset for weapons
|
||||
const int currentweapon = EMU_ReadInt(playerbase[player] + GE_currentweapon);
|
||||
const float fovratio = fov / basefov, fovmodifier = basefov / 60.f; // basefov is 60 unless override is above 60
|
||||
const float threshold = 0.72f, speed = 475.f, sensitivity = 292.f * fovmodifier;
|
||||
const int aimingintank = EMU_ReadInt(GE_tankflag) == 1 && currentweapon == 32; // flag if player is driving tank with tank equipped as weapon
|
||||
if(aimingflag) // if player is aiming
|
||||
{
|
||||
const float mouseaccel = PROFILE[player].SETTINGS[ACCELERATION] ? sqrt(DEVICE[player].XPOS * DEVICE[player].XPOS + DEVICE[player].YPOS * DEVICE[player].YPOS) / TICKRATE / 12.0f * PROFILE[player].SETTINGS[ACCELERATION] : 0;
|
||||
crosshairposx[player] += DEVICE[player].XPOS / 10.0f * (PROFILE[player].SETTINGS[SENSITIVITY] / sensitivity / RATIOFACTOR) * fmax(mouseaccel, 1); // calculate the crosshair position
|
||||
crosshairposy[player] += (!PROFILE[player].SETTINGS[INVERTPITCH] ? DEVICE[player].YPOS : -DEVICE[player].YPOS) / 10.0f * (PROFILE[player].SETTINGS[SENSITIVITY] / sensitivity) * fmax(mouseaccel, 1);
|
||||
crosshairposx[player] = ClampFloat(crosshairposx[player], -CROSSHAIRLIMIT, CROSSHAIRLIMIT); // apply clamp then inject
|
||||
crosshairposy[player] = ClampFloat(crosshairposy[player], -CROSSHAIRLIMIT, CROSSHAIRLIMIT);
|
||||
if(aimingintank) // if player is aiming while driving tank with tank equipped as weapon, set x axis crosshair to 0 (like the original game - so you cannot aim across the screen because the tank barrel is locked in the center)
|
||||
crosshairposx[player] = 0;
|
||||
EMU_WriteFloat(playerbase[player] + GE_crosshairx, crosshairposx[player]);
|
||||
EMU_WriteFloat(playerbase[player] + GE_crosshairy, crosshairposy[player]);
|
||||
EMU_WriteFloat(playerbase[player] + GE_gunx, crosshairposx[player] * RATIOFACTOR * (1.11f + (currentweapon >= 0 && currentweapon <= 32 ? offsetpos[0][currentweapon] : 0.15f) * 1.5f) + fovratio - 1); // calculate and inject the gun angles (uses pre-made pos table or if unknown weapon use fail-safe value)
|
||||
EMU_WriteFloat(playerbase[player] + GE_guny, crosshairposy[player] * (1.11f + (currentweapon >= 0 && currentweapon <= 32 ? offsetpos[1][currentweapon] : 0) * 1.5f) + fovratio - 1);
|
||||
if(crosshairx > 0 && crosshairx / CROSSHAIRLIMIT > threshold) // if crosshair is within threshold of the border then calculate a linear scrolling speed and enable mouselook
|
||||
aimx[player] = (crosshairx / CROSSHAIRLIMIT - threshold) * speed * TIMESTEP;
|
||||
else if(crosshairx < 0 && crosshairx / CROSSHAIRLIMIT < -threshold)
|
||||
aimx[player] = (crosshairx / CROSSHAIRLIMIT + threshold) * speed * TIMESTEP;
|
||||
else
|
||||
aimx[player] = 0;
|
||||
if(crosshairy > 0 && crosshairy / CROSSHAIRLIMIT > threshold)
|
||||
aimy[player] = (crosshairy / CROSSHAIRLIMIT - threshold) * speed * TIMESTEP;
|
||||
else if(crosshairy < 0 && crosshairy / CROSSHAIRLIMIT < -threshold)
|
||||
aimy[player] = (crosshairy / CROSSHAIRLIMIT + threshold) * speed * TIMESTEP;
|
||||
else
|
||||
aimy[player] = 0;
|
||||
}
|
||||
else // player is not aiming so reset crosshairposxy values
|
||||
crosshairposx[player] = crosshairx, crosshairposy[player] = crosshairy;
|
||||
}
|
||||
//==========================================================================
|
||||
// Purpose: calculate and send emulator key combo
|
||||
//==========================================================================
|
||||
static void GE_Controller(void)
|
||||
{
|
||||
for(int player = PLAYER1; player < ALLPLAYERS; player++)
|
||||
{
|
||||
CONTROLLER[player].U_CBUTTON = DEVICE[player].BUTTONPRIM[FORWARDS] || DEVICE[player].BUTTONSEC[FORWARDS];
|
||||
CONTROLLER[player].D_CBUTTON = DEVICE[player].BUTTONPRIM[BACKWARDS] || DEVICE[player].BUTTONSEC[BACKWARDS];
|
||||
CONTROLLER[player].L_CBUTTON = DEVICE[player].BUTTONPRIM[STRAFELEFT] || DEVICE[player].BUTTONSEC[STRAFELEFT];
|
||||
CONTROLLER[player].R_CBUTTON = DEVICE[player].BUTTONPRIM[STRAFERIGHT] || DEVICE[player].BUTTONSEC[STRAFERIGHT];
|
||||
CONTROLLER[player].Z_TRIG = DEVICE[player].BUTTONPRIM[FIRE] || DEVICE[player].BUTTONSEC[FIRE] || DEVICE[player].BUTTONPRIM[PREVIOUSWEAPON] || DEVICE[player].BUTTONSEC[PREVIOUSWEAPON];
|
||||
CONTROLLER[player].R_TRIG = DEVICE[player].BUTTONPRIM[AIM] || DEVICE[player].BUTTONSEC[AIM];
|
||||
#ifndef SPEEDRUN_BUILD // speedrun build does not have reload button support
|
||||
CONTROLLER[player].RELOAD_HACK = DEVICE[player].BUTTONPRIM[RELOAD] || DEVICE[player].BUTTONSEC[RELOAD];
|
||||
#endif
|
||||
CONTROLLER[player].A_BUTTON = DEVICE[player].BUTTONPRIM[ACCEPT] || DEVICE[player].BUTTONSEC[ACCEPT] || DEVICE[player].BUTTONPRIM[PREVIOUSWEAPON] || DEVICE[player].BUTTONSEC[PREVIOUSWEAPON] || DEVICE[player].BUTTONPRIM[NEXTWEAPON] || DEVICE[player].BUTTONSEC[NEXTWEAPON];
|
||||
CONTROLLER[player].B_BUTTON = DEVICE[player].BUTTONPRIM[CANCEL] || DEVICE[player].BUTTONSEC[CANCEL];
|
||||
CONTROLLER[player].START_BUTTON = DEVICE[player].BUTTONPRIM[START] || DEVICE[player].BUTTONSEC[START];
|
||||
DEVICE[player].ARROW[0] = (DEVICE[player].BUTTONPRIM[UP] || DEVICE[player].BUTTONSEC[UP]) ? 127 : 0;
|
||||
DEVICE[player].ARROW[1] = (DEVICE[player].BUTTONPRIM[DOWN] || DEVICE[player].BUTTONSEC[DOWN]) ? (EMU_ReadInt(GE_menupage) != 11 ? -127 : -128) : 0; // clamp to -127 for menus due to overflow bug
|
||||
DEVICE[player].ARROW[2] = (DEVICE[player].BUTTONPRIM[LEFT] || DEVICE[player].BUTTONSEC[LEFT]) ? -128 : 0;
|
||||
DEVICE[player].ARROW[3] = (DEVICE[player].BUTTONPRIM[RIGHT] || DEVICE[player].BUTTONSEC[RIGHT]) ? 127 : 0;
|
||||
CONTROLLER[player].X_AXIS = DEVICE[player].ARROW[0] + DEVICE[player].ARROW[1];
|
||||
CONTROLLER[player].Y_AXIS = DEVICE[player].ARROW[2] + DEVICE[player].ARROW[3];
|
||||
}
|
||||
if(EMU_ReadInt(GE_menupage) != 11 && !CONTROLLER[PLAYER1].B_BUTTON) // pressing aim will act like the back button (only in menus and for player 1)
|
||||
CONTROLLER[PLAYER1].B_BUTTON = DEVICE[PLAYER1].BUTTONPRIM[AIM] || DEVICE[PLAYER1].BUTTONSEC[AIM];
|
||||
}
|
||||
//==========================================================================
|
||||
// Purpose: inject hacks into rom before code has been cached
|
||||
//==========================================================================
|
||||
static void GE_InjectHacks(void)
|
||||
{
|
||||
const int addressarray[27] = {0x000B7EA0, 0x000B7EB8, 0x0009C7F8, 0x0009C7FC, 0x0009C80C, 0x0009C810, 0x0009C998, 0x0009C99C, 0x0009C9AC, 0x0009C9B0, 0x000AE4DC, 0x000AE4E0, 0x000AE4E4, 0x000AE4E8, 0x000AE4EC, 0x000AE4F0, 0x000AE4F4, 0x000AE4F8, 0x000AE4FC, 0x000AE500, 0x000AE504, 0x000AE508, 0x000AE50C, 0x000AE510, 0x000AE514, 0x000AE518, 0x000AE51C}, codearray[27] = {0x00000000, 0x00000000, 0x0BC1E66B, 0x460C5100, 0x0BC1E66F, 0x460E3280, 0x0BC1E673, 0x460C4100, 0x0BC1E677, 0x460E5200, 0x8C590124, 0x53200001, 0xE4440FF0, 0x0BC19F34, 0x8C590124, 0x53200001, 0xE44A0FF4, 0x0BC19F39, 0x8C590124, 0x53200001, 0xE4441004, 0x0BC19F9C, 0x8C590124, 0x53200001, 0xE4481008, 0x0BC19FA1, 0x00000000}; // disable autostand code, add branch to crosshair code so cursor aiming mode is absolute (without jitter)
|
||||
for(int index = 0; index < 27; index++) // inject code array
|
||||
EMU_WriteROM(addressarray[index], codearray[index]);
|
||||
#ifndef SPEEDRUN_BUILD // gives unfair advantage, remove for speedrun build
|
||||
const int reloadhack_address[23] = {0x000B7754, 0x000B6EC0, 0x000B7508, 0x000B750C, 0x000B7510, 0x000B7514, 0x000B7518, 0x000B751C, 0x000B7520, 0x000BEA68, 0x000BEA6C, 0x000BEA74, 0x000F30FC, 0x000F3100, 0x000F3104, 0x000F3108, 0x000F310C, 0x000F3110, 0x000F3114, 0x000F3118, 0x000F311C, 0x000F3120, 0x000F3124}, reloadhack_code[23] = {0x8FAB01C8, 0x304F4040, 0x330D4000, 0x51A00091, 0x8E0D0000, 0x3C028003, 0x8C4D6448, 0x11A0002D, 0x8C4C6450, 0x8C4200D0, 0x304B0040, 0x304A4000, 0x8E020000, 0x51600005, 0x00000000, 0x0FC17659, 0x00002025, 0x0FC17659, 0x24040001, 0x11400003, 0x00000000, 0x0FC0F13C, 0x00000000}; // add reload button hack
|
||||
for(int index = 0; index < 23; index++) // inject code array
|
||||
EMU_WriteROM(reloadhack_address[index], reloadhack_code[index]);
|
||||
if((unsigned int)EMU_ReadROM(GE_controlstyle) == 0x8DC22A58) // if safe to overwrite
|
||||
EMU_WriteROM(GE_controlstyle, 0x34020001); // always force game to use 1.2 control style
|
||||
if((unsigned int)EMU_ReadROM(GE_reversepitch) == 0x8C420A84) // if safe to overwrite
|
||||
EMU_WriteROM(GE_reversepitch, 0x34020001); // always force game to use upright pitch
|
||||
if((unsigned int)EMU_ReadInt(GE_pickupyaxisthreshold) == 0xBF490FDB && EMU_ReadInt(GE_menupage) == 0) // if safe to overwrite
|
||||
EMU_WriteFloat(GE_pickupyaxisthreshold, -60.f * PI / 180.f); // overwrite default y axis limit for picking up items (from -45 to -60)
|
||||
if(OVERRIDEFOV != 60) // override default fov
|
||||
{
|
||||
float newfov = OVERRIDEFOV;
|
||||
unsigned int unsignedinteger = *(unsigned int *)(float *)(&newfov);
|
||||
EMU_WriteROM(GE_defaultfov, 0x3C010000 + (short)(unsignedinteger / 0x10000));
|
||||
EMU_WriteROM(GE_defaultfovinit, 0x3C010000 + (short)(unsignedinteger / 0x10000));
|
||||
EMU_WriteROM(GE_defaultfovzoom, 0x3C010000 + (short)(unsignedinteger / 0x10000));
|
||||
if(!bypassviewmodelfovtweak) // allow user to bypass viewmodel position compensation for override fov (so they can see more detail at the expense of introducing draw order glitches)
|
||||
{
|
||||
if(EMU_ReadInt(GE_weaponypos) == 0 && EMU_ReadInt(GE_weaponzpos) == 0) // if first weapon slot position is default
|
||||
{
|
||||
for(int index = 0; index <= 32; index++) // cycle through first 32 weapons
|
||||
{
|
||||
const float fovoffset = OVERRIDEFOV - 60;
|
||||
const float weaponypos = EMU_ReadFloat(GE_weaponypos + (index * 0x70)) - (fovoffset / (2.25f * 4.f)); // adjust weapon Y/Z positions for override field of view
|
||||
const float weaponzpos = EMU_ReadFloat(GE_weaponzpos + (index * 0x70)) + (fovoffset / 2.75f);
|
||||
EMU_WriteFloat(GE_weaponypos + (index * 0x70), weaponypos);
|
||||
EMU_WriteFloat(GE_weaponzpos + (index * 0x70), weaponzpos);
|
||||
}
|
||||
}
|
||||
}
|
||||
if(OVERRIDEFOV > 60)
|
||||
EMU_WriteFloat(GE_defaultzoomspeed, (OVERRIDEFOV - 60) * ((1.7f - 0.909091f) / 60.0f) + 0.909091f); // adjust zoom speed default (0.909091 default, 1.7 max)
|
||||
}
|
||||
if((unsigned int)EMU_ReadInt(GE_defaultratio) == 0x3FE38E39 && (overrideratiowidth != 16 || overrideratioheight != 9)) // override default 16:9 ratio
|
||||
{
|
||||
EMU_WriteFloat(GE_defaultratio, (float)overrideratiowidth / (float)overrideratioheight); // apply new ratio
|
||||
float newratio = (4.f / 3.f) / ((float)overrideratiowidth / (float)overrideratioheight); // now apply ratio factor to crosshair scale
|
||||
unsigned int unsignedinteger = *(unsigned int *)(float *)(&newratio);
|
||||
EMU_WriteROM(GE_defaultratiocrosshair, 0x3C010000 + (short)(unsignedinteger / 0x10000));
|
||||
}
|
||||
#endif
|
||||
if(geshowcrosshair) // inject show crosshair hack
|
||||
{
|
||||
EMU_WriteROM(GE_showcrosshair, 0x8C4E01C8); // replace lw $t6, 0x1128 ($v0) (8C4E1128) with lw $t6, 0x01C8 ($v0) (8C4E01C8)
|
||||
if(EMU_ReadROM(GE_crosshairimage) == 0x000008BC && EMU_ReadROM(0x28) != 0x45522020) // if crosshair image found and rom isn't Goldfinger 64 (why? because GF64 replaced beta crosshair image with ammo icon)
|
||||
EMU_WriteROM(GE_crosshairimage, 0x000008BD); // replace crosshair image with beta crosshair
|
||||
}
|
||||
if(CONTROLLER[PLAYER1].Z_TRIG && CONTROLLER[PLAYER1].R_TRIG) // skip intros if holding down fire + aim
|
||||
{
|
||||
EMU_WriteInt(GE_introcounter, 0x00001000);
|
||||
EMU_WriteInt(GE_seenintroflag, 0);
|
||||
}
|
||||
}
|
||||
//==========================================================================
|
||||
// Purpose: run when emulator closes rom
|
||||
// Changes Globals: playerbase, safetocrouch, safetostand, crouchstance
|
||||
//==========================================================================
|
||||
void GE_Quit(void)
|
||||
{
|
||||
for(int player = PLAYER1; player < ALLPLAYERS; player++)
|
||||
{
|
||||
playerbase[player] = 0;
|
||||
GE_ResetCrouchToggle(player);
|
||||
}
|
||||
}
|
||||
@@ -1,101 +0,0 @@
|
||||
//==========================================================================
|
||||
// Mouse Injector Plugin
|
||||
//==========================================================================
|
||||
// Copyright (C) 2016-2021 Carnivorous
|
||||
// All rights reserved.
|
||||
//
|
||||
// Mouse Injector 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, visit http://www.gnu.org/licenses/gpl-2.0.html
|
||||
//==========================================================================
|
||||
#define LOAD_SHALF_PARAM(param) *(short *) ((unsigned char *)rdramptr[(((param) >> 12))] + (((param) & 0x00000FFF) ^ 2))
|
||||
#define LOAD_SWORD_PARAM(param) *(int *)((unsigned char *)rdramptr[(((param) >> 12))] + (((param) & 0x00000FFF)))
|
||||
#define LOAD_UWORD_PARAM(param) *(unsigned int *)((unsigned char *)rdramptr[(((param) >> 12))] + (((param) & 0x00000FFF)))
|
||||
|
||||
#define WITHINRANGE(param) ((rdramptr != 0) && ((param & 0xFF800000U) == 0x80000000U))
|
||||
#define GARBAGESHORT (short)0xABAD
|
||||
#define GARBAGEINT (int)0xABADC0DE
|
||||
|
||||
//==========================================================================
|
||||
// Purpose: read short from memory
|
||||
// Parameter: address
|
||||
//==========================================================================
|
||||
static inline short EMU_ReadShort(const unsigned int addr)
|
||||
{
|
||||
if(WITHINRANGE(addr))
|
||||
return LOAD_SHALF_PARAM(addr);
|
||||
return GARBAGESHORT;
|
||||
}
|
||||
//==========================================================================
|
||||
// Purpose: write short to memory location
|
||||
// Parameter: address, value
|
||||
//==========================================================================
|
||||
static inline void EMU_WriteShort(const unsigned int addr, const short value)
|
||||
{
|
||||
if(WITHINRANGE(addr))
|
||||
LOAD_SHALF_PARAM(addr) = value;
|
||||
}
|
||||
//==========================================================================
|
||||
// Purpose: read int from memory
|
||||
// Parameter: address
|
||||
//==========================================================================
|
||||
static inline int EMU_ReadInt(const unsigned int addr)
|
||||
{
|
||||
if(WITHINRANGE(addr))
|
||||
return LOAD_SWORD_PARAM(addr);
|
||||
return GARBAGEINT;
|
||||
}
|
||||
//==========================================================================
|
||||
// Purpose: write int to memory location
|
||||
// Parameter: address, value
|
||||
//==========================================================================
|
||||
static inline void EMU_WriteInt(const unsigned int addr, const int value)
|
||||
{
|
||||
if(WITHINRANGE(addr))
|
||||
LOAD_SWORD_PARAM(addr) = value;
|
||||
}
|
||||
//==========================================================================
|
||||
// Purpose: read float from memory
|
||||
// Parameter: address
|
||||
//==========================================================================
|
||||
static inline float EMU_ReadFloat(const unsigned int addr)
|
||||
{
|
||||
if(WITHINRANGE(addr))
|
||||
return *((float *)&LOAD_UWORD_PARAM(addr));
|
||||
return GARBAGEINT;
|
||||
}
|
||||
//==========================================================================
|
||||
// Purpose: write float to memory location
|
||||
// Parameter: address, value
|
||||
//==========================================================================
|
||||
static inline void EMU_WriteFloat(const unsigned int addr, const float value)
|
||||
{
|
||||
if(WITHINRANGE(addr))
|
||||
LOAD_UWORD_PARAM(addr) = *(unsigned int *)(&value);
|
||||
}
|
||||
//==========================================================================
|
||||
// Purpose: read int from emulator's copy of rom
|
||||
// Parameter: address
|
||||
//==========================================================================
|
||||
static inline unsigned EMU_ReadROM(const unsigned int addr)
|
||||
{
|
||||
return (unsigned)romptr[addr / 0x4];
|
||||
}
|
||||
//==========================================================================
|
||||
// Purpose: write to emulator's copy of rom
|
||||
// Parameter: address, value
|
||||
//==========================================================================
|
||||
static inline void EMU_WriteROM(const unsigned int addr, const unsigned int value)
|
||||
{
|
||||
if(romptr != 0)
|
||||
romptr[addr / 0x4] = (void *)value;
|
||||
}
|
||||
@@ -1,555 +0,0 @@
|
||||
//==========================================================================
|
||||
// Mouse Injector Plugin
|
||||
//==========================================================================
|
||||
// Copyright (C) 2016-2021 Carnivorous
|
||||
// All rights reserved.
|
||||
//
|
||||
// Mouse Injector 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, visit http://www.gnu.org/licenses/gpl-2.0.html
|
||||
//==========================================================================
|
||||
#include <math.h>
|
||||
#include "../global.h"
|
||||
#include "../maindll.h"
|
||||
#include "game.h"
|
||||
#include "memory.h"
|
||||
|
||||
#define GUNAIMLIMIT 14.12940025 // 0x41621206
|
||||
#define CROSSHAIRLIMIT 18.76135635 // 0x41961742
|
||||
#define GUNRECOILXLIMIT 756.1247559 // 0x443D07FC
|
||||
#define GUNRECOILYLIMIT 57.63883972 // 0x42668E2C
|
||||
#define BIKEXROTATIONLIMIT 6.282184601 // 0x40C907A8
|
||||
#define BIKEROLLLIMIT 0.7852724195 // 0xBF49079D/0x3F49079D
|
||||
#define PI 3.1415927 // 0x40490FDB
|
||||
// PERFECT DARK ADDRESSES - OFFSET ADDRESSES BELOW (REQUIRES PLAYERBASE/BIKEBASE TO USE)
|
||||
#define PD_stanceflag 0x801BB74C - 0x801BB6A0
|
||||
#define PD_deathflag 0x801BB778 - 0x801BB6A0
|
||||
#define PD_camx 0x801BB7E4 - 0x801BB6A0
|
||||
#define PD_camy 0x801BB7F4 - 0x801BB6A0
|
||||
#define PD_fov 0x801BCEE8 - 0x801BB6A0
|
||||
#define PD_crosshairx 0x801BCD08 - 0x801BB6A0
|
||||
#define PD_crosshairy 0x801BCD0C - 0x801BB6A0
|
||||
#define PD_grabflag 0x801BB850 - 0x801BB6A0
|
||||
#define PD_bikeptr 0x801BD10C - 0x801BB6A0
|
||||
#define PD_thirdperson 0x801BB6A0 - 0x801BB6A0
|
||||
#define PD_gunrx 0x801BC374 - 0x801BB6A0
|
||||
#define PD_gunry 0x801BC378 - 0x801BB6A0
|
||||
#define PD_gunlx 0x801BCB18 - 0x801BB6A0
|
||||
#define PD_gunly 0x801BCB1C - 0x801BB6A0
|
||||
#define PD_aimingflag 0x801BB7C0 - 0x801BB6A0
|
||||
#define PD_gunrstate 0x801BC2DC - 0x801BB6A0
|
||||
#define PD_gunlstate 0x801BCA80 - 0x801BB6A0
|
||||
#define PD_gunrxrecoil 0x801BBE98 - 0x801BB6A0
|
||||
#define PD_gunryrecoil 0x801BBE9C - 0x801BB6A0
|
||||
#define PD_gunlxrecoil 0x801BC63C - 0x801BB6A0
|
||||
#define PD_gunlyrecoil 0x801BC640 - 0x801BB6A0
|
||||
#define PD_currentweapon 0x801BCC28 - 0x801BB6A0
|
||||
#define PD_bikebase 0x805142C4 - 0x805142C0
|
||||
#define PD_bikeyaw 0x804B1AB4 - 0x804B1A48
|
||||
#define PD_bikeroll 0x804B1B04 - 0x804B1A48
|
||||
#define PD_camspybase 0x801BBB20 - 0x801BB6A0
|
||||
#define PD_camspyflag 0x801BB6D4 - 0x801BB6A0
|
||||
#define PD_camspyx 0x80607EEC - 0x80607ED0
|
||||
#define PD_camspyy 0x80607EF8 - 0x80607ED0
|
||||
#define PD_camspyycos 0x80607EFC - 0x80607ED0
|
||||
#define PD_camspyysin 0x80607F00 - 0x80607ED0
|
||||
// STATIC ADDRESSES BELOW
|
||||
#define JOANNADATA(X) (unsigned int)EMU_ReadInt(0x8009A024 + (X * 0x4)) // player pointer address (0x4 offset for each players)
|
||||
#define PD_menu(X) 0x80070750 + (X * 0x4) // player menu flag (0 = PD is in menu) (0x4 offset for each players)
|
||||
#define PD_camera 0x8009A26C // camera flag (1 = gameplay, 2 & 3 = ???, 4 = multiplayer sweep, 5 = gameover screen, 6 = cutscene mode, 7 = force player to move: extraction's dark room)
|
||||
#define PD_pause 0x80084014 // menu flag (1 = PD is paused)
|
||||
#define PD_stageid 0x800624E4 // stage id
|
||||
#define PD_debugtext 0x803C79F0 // debug text (used to check if PD is running)
|
||||
#define PD_mppause 0x800ACBA6 // used to check if multiplayer match is paused
|
||||
#define PD_defaultratio 0x803CD680 // 16:9 ratio default
|
||||
#define PD_defaultfov 0x802EAA5C // field of view default
|
||||
#define PD_defaultfovzoom 0x802EACFC // field of view default for zoom
|
||||
#define PD_defaultzoominspeed 0x802DA8F8 // default zoom in speed
|
||||
#define PD_defaultzoomoutspeed 0x802DA924 // default zoom out speed
|
||||
#define PD_introcounter 0x800624C4 // counter for intro
|
||||
#define PD_controlstyle 0x80372728 // instruction reads the current controller style
|
||||
#define PD_reversepitch 0x803727A0 // instruction reads the current reverse pitch option
|
||||
#define PD_pickupyaxisthreshold 0x803CAE78 // y axis threshold on picking up weapons
|
||||
#define PD_weapontable 0x8006FF1C // weapon pointer table, used to change view model positions
|
||||
#define PD_radialmenutimer 0x802EA2BC // time instruction for radial menu to appear (15 ticks)
|
||||
#define PD_radialmenualphainit 0x803D2CDC // initial alpha value for all menus
|
||||
#define PD_blurfix 0x802DB68C // nop gap on chr function to store our blur fix
|
||||
#define PD_hiresoption 0x80322D9C // argument used to set hires mode on within options
|
||||
#define PD_camspylookspringup 0x802F13E8 // save instruction for adjusted camspy look spring pitch
|
||||
#define PD_camspylookspringdown 0x802F143C // save instruction for adjusted camspy look spring pitch
|
||||
|
||||
static unsigned int playerbase[4] = {0}; // current player's joannadata address
|
||||
static int xstick[4] = {0}, ystick[4] = {0}, usingstick[4] = {0}, slayerairbrakes[4] = {0}; // for camspy/slayer controls
|
||||
static float xmenu[4] = {0}, ymenu[4] = {0}; // for pd radial nav function
|
||||
static int radialmenudirection[4][4] = {{0}, {0}, {0}, {0}}; // used to override c buttons if user is interacting with a radial menu
|
||||
static int safetocrouch[4] = {1, 1, 1, 1}, safetostand[4] = {0}, crouchstance[4] = {2, 2, 2, 2}; // used for crouch toggle (limits tick-tocking)
|
||||
static int safetolowercamspy[4] = {0}, safetoraisecamspy[4] = {1, 1, 1, 1}, camspystance[4] = {1, 1, 1, 1}; // used for lowering/raising camspy height
|
||||
static float crosshairposx[4], crosshairposy[4], aimx[4], aimy[4];
|
||||
static int gunrcenter[4], gunlcenter[4];
|
||||
|
||||
int PD_Status(void);
|
||||
void PD_Inject(void);
|
||||
static void PD_Crouch(const int player);
|
||||
#define PD_ResetCrouchToggle(X) safetocrouch[X] = 1, safetostand[X] = 0, crouchstance[X] = 2 // reset crouch toggle bind
|
||||
#define PD_ResetCamspyStance(X) safetolowercamspy[X] = 0, safetoraisecamspy[X] = 1, camspystance[X] = 1 // reset camspy stance
|
||||
#define PD_ResetCamspySlayerStick(X) xstick[X] = 0, ystick[X] = 0, usingstick[X] = 0, slayerairbrakes[X] = 0 // reset x/y stick array for camspy/slayer
|
||||
#define PD_ResetRadialMenuBtns(X) for(int direction = 0; direction < 4; direction++) radialmenudirection[X][direction] = 0 // reset direction buttons
|
||||
static void PD_AimMode(const int player, const int aimingflag, const float fov, const float basefov);
|
||||
static void PD_CamspySlayer(const int player, const int camspyflag, const float sensitivity);
|
||||
static void PD_RadialMenuNav(const int player);
|
||||
static void PD_Controller(void);
|
||||
static void PD_InjectHacks(void);
|
||||
void PD_Quit(void);
|
||||
|
||||
static const GAMEDRIVER GAMEDRIVER_INTERFACE =
|
||||
{
|
||||
"Perfect Dark",
|
||||
PD_Status,
|
||||
PD_Inject,
|
||||
PD_Quit
|
||||
};
|
||||
|
||||
const GAMEDRIVER *GAME_PERFECTDARK = &GAMEDRIVER_INTERFACE;
|
||||
|
||||
//==========================================================================
|
||||
// Purpose: returns a value, which is then used to check what game is running in game.c
|
||||
// Q: What is happening here?
|
||||
// A: We look up some static addresses and if the values are within the expected ranges the program can assume that the game is currently running
|
||||
//==========================================================================
|
||||
int PD_Status(void)
|
||||
{
|
||||
const int pd_menu = EMU_ReadInt(PD_menu(PLAYER1)), pd_camera = EMU_ReadInt(PD_camera), pd_pause = EMU_ReadInt(PD_pause), pd_romcheck = EMU_ReadInt(PD_debugtext);
|
||||
return (pd_menu >= 0 && pd_menu <= 1 && pd_camera >= 0 && pd_camera <= 7 && pd_pause >= 0 && pd_pause <= 1 && pd_romcheck == 0x206F6620); // if Perfect Dark is current game
|
||||
}
|
||||
//==========================================================================
|
||||
// Purpose: calculate mouse movement and inject into current game
|
||||
// Changes Globals: safetocrouch, safetostand, crouchstance
|
||||
//==========================================================================
|
||||
void PD_Inject(void)
|
||||
{
|
||||
if(EMU_ReadInt(PD_stageid) < 1) // hacks can only be injected at boot sequence before code blocks are cached, so inject until player has spawned
|
||||
PD_InjectHacks();
|
||||
const int camera = EMU_ReadInt(PD_camera);
|
||||
const int pause = EMU_ReadInt(PD_pause);
|
||||
const int mppause = (EMU_ReadShort(PD_mppause) & 0xFF00);
|
||||
for(int player = PLAYER1; player < ALLPLAYERS; player++)
|
||||
{
|
||||
if(PROFILE[player].SETTINGS[CONFIG] == DISABLED) // bypass disabled players
|
||||
continue;
|
||||
playerbase[player] = JOANNADATA(player);
|
||||
const int dead = EMU_ReadInt(playerbase[player] + PD_deathflag);
|
||||
const int menu = EMU_ReadInt(PD_menu(player));
|
||||
const int aimingflag = EMU_ReadInt(playerbase[player] + PD_aimingflag);
|
||||
const int grabflag = EMU_ReadInt(playerbase[player] + PD_grabflag);
|
||||
const unsigned int bikebase = EMU_ReadInt((unsigned int)EMU_ReadInt(playerbase[player] + PD_bikeptr) + PD_bikebase);
|
||||
const int thirdperson = EMU_ReadInt(playerbase[player] + PD_thirdperson);
|
||||
const int cursoraimingflag = PROFILE[player].SETTINGS[PDAIMMODE] && aimingflag && EMU_ReadInt(playerbase[player] + PD_currentweapon) != 50; // don't use cursoraiming when using the horizon scanner
|
||||
const float fov = EMU_ReadFloat(playerbase[player] + PD_fov);
|
||||
const float basefov = fov > 60.0f ? (float)OVERRIDEFOV : 60.0f;
|
||||
const float mouseaccel = PROFILE[player].SETTINGS[ACCELERATION] ? sqrt(DEVICE[player].XPOS * DEVICE[player].XPOS + DEVICE[player].YPOS * DEVICE[player].YPOS) / TICKRATE / 12.0f * PROFILE[player].SETTINGS[ACCELERATION] : 0;
|
||||
const float sensitivity = PROFILE[player].SETTINGS[SENSITIVITY] / 40.0f * fmax(mouseaccel, 1);
|
||||
const float gunsensitivity = sensitivity * (PROFILE[player].SETTINGS[CROSSHAIR] / 2.5f);
|
||||
float camx = EMU_ReadFloat(playerbase[player] + PD_camx), camy = EMU_ReadFloat(playerbase[player] + PD_camy);
|
||||
if(camx >= 0 && camx <= 360 && camy >= -90 && camy <= 90 && fov >= 1 && fov <= FOV_MAX && dead == 0 && menu == 1 && pause == 0 && mppause == 0 && camera == 1 && (grabflag == 0 || grabflag == 4 || grabflag == 3)) // if safe to inject
|
||||
{
|
||||
if(thirdperson == 1 || thirdperson == 2) // if player is using the slayer/camspy, memory inject camspy/translate mouse input to analog stick and continue to next player
|
||||
{
|
||||
PD_CamspySlayer(player, thirdperson == 2, sensitivity);
|
||||
continue;
|
||||
}
|
||||
PD_AimMode(player, cursoraimingflag, fov, basefov);
|
||||
if(grabflag != 3) // if player is on foot
|
||||
{
|
||||
PD_Crouch(player);
|
||||
if(!cursoraimingflag) // if not aiming (or pdaimmode is off)
|
||||
camx += DEVICE[player].XPOS / 10.0f * sensitivity * (fov / basefov); // regular mouselook calculation
|
||||
else
|
||||
camx += aimx[player] * (fov / basefov); // scroll screen with aimx/aimy
|
||||
while(camx < 0)
|
||||
camx += 360;
|
||||
while(camx >= 360)
|
||||
camx -= 360;
|
||||
EMU_WriteFloat(playerbase[player] + PD_camx, camx);
|
||||
}
|
||||
else if(WITHINRANGE(bikebase)) // if player is riding hoverbike (and hoverbike address is legal)
|
||||
{
|
||||
PD_ResetCrouchToggle(player);
|
||||
float bikeyaw = EMU_ReadFloat(bikebase + PD_bikeyaw), bikeroll = EMU_ReadFloat(bikebase + PD_bikeroll);
|
||||
if(!cursoraimingflag)
|
||||
{
|
||||
bikeyaw -= DEVICE[player].XPOS / 10.0f * sensitivity / (360 / BIKEXROTATIONLIMIT) * (fov / basefov);
|
||||
bikeroll += DEVICE[player].XPOS / 10.0f * sensitivity * (fov / basefov) / 100;
|
||||
}
|
||||
else
|
||||
{
|
||||
bikeyaw -= aimx[player] / (360 / BIKEXROTATIONLIMIT) * (fov / basefov);
|
||||
bikeroll += aimx[player] * sensitivity * (fov / basefov) / 100;
|
||||
}
|
||||
while(bikeyaw < 0)
|
||||
bikeyaw += BIKEXROTATIONLIMIT;
|
||||
while(bikeyaw >= BIKEXROTATIONLIMIT)
|
||||
bikeyaw -= BIKEXROTATIONLIMIT;
|
||||
bikeroll = ClampFloat(bikeroll, -BIKEROLLLIMIT, BIKEROLLLIMIT);
|
||||
EMU_WriteFloat(bikebase + PD_bikeyaw, bikeyaw);
|
||||
EMU_WriteFloat(bikebase + PD_bikeroll, bikeroll);
|
||||
}
|
||||
if(!cursoraimingflag)
|
||||
camy += (!PROFILE[player].SETTINGS[INVERTPITCH] ? -DEVICE[player].YPOS : DEVICE[player].YPOS) / 10.0f * sensitivity * (fov / basefov);
|
||||
else
|
||||
camy += -aimy[player] * (fov / basefov);
|
||||
camy = ClampFloat(camy, -90, 90);
|
||||
EMU_WriteFloat(playerbase[player] + PD_camy, camy);
|
||||
if(PROFILE[player].SETTINGS[CROSSHAIR] && !cursoraimingflag) // if crosshair movement is enabled and player isn't aiming (don't calculate weapon movement while the player is in aim mode)
|
||||
{
|
||||
float gunx = EMU_ReadFloat(playerbase[player] + PD_gunrx), crosshairx = EMU_ReadFloat(playerbase[player] + PD_crosshairx); // after camera x and y have been calculated and injected, calculate the gun/reload/crosshair movement
|
||||
gunx += DEVICE[player].XPOS / (!aimingflag ? 10.0f : 40.0f) * gunsensitivity * (fov / basefov) * 0.05f / RATIOFACTOR;
|
||||
crosshairx += DEVICE[player].XPOS / (!aimingflag ? 10.0f : 40.0f) * gunsensitivity * (fov / 4 / (basefov / 4)) * 0.05f / RATIOFACTOR;
|
||||
if(aimingflag) // emulate cursor moving back to the center
|
||||
gunx /= emuoverclock ? 1.03f : 1.07f, crosshairx /= emuoverclock ? 1.03f : 1.07f;
|
||||
gunx = ClampFloat(gunx, -GUNAIMLIMIT, GUNAIMLIMIT);
|
||||
crosshairx = ClampFloat(crosshairx, -CROSSHAIRLIMIT, CROSSHAIRLIMIT);
|
||||
EMU_WriteFloat(playerbase[player] + PD_gunrx, gunx);
|
||||
EMU_WriteFloat(playerbase[player] + PD_gunrxrecoil, crosshairx * (GUNRECOILXLIMIT / CROSSHAIRLIMIT));
|
||||
EMU_WriteFloat(playerbase[player] + PD_gunlx, gunx);
|
||||
EMU_WriteFloat(playerbase[player] + PD_gunlxrecoil, crosshairx * (GUNRECOILXLIMIT / CROSSHAIRLIMIT));
|
||||
EMU_WriteFloat(playerbase[player] + PD_crosshairx, crosshairx);
|
||||
if(camy > -90 && camy < 90) // only allow player's gun to pitch within a valid range
|
||||
{
|
||||
float guny = EMU_ReadFloat(playerbase[player] + PD_gunry), crosshairy = EMU_ReadFloat(playerbase[player] + PD_crosshairy);
|
||||
guny += (!PROFILE[player].SETTINGS[INVERTPITCH] ? DEVICE[player].YPOS : -DEVICE[player].YPOS) / (!aimingflag ? 10.0f : 40.0f) * gunsensitivity * (fov / basefov) * 0.075f;
|
||||
crosshairy += (!PROFILE[player].SETTINGS[INVERTPITCH] ? DEVICE[player].YPOS : -DEVICE[player].YPOS) / (!aimingflag ? 10.0f : 40.0f) * gunsensitivity * (fov / 4 / (basefov / 4)) * 0.1f;
|
||||
if(aimingflag)
|
||||
guny /= emuoverclock ? 1.15f : 1.35f, crosshairy /= emuoverclock ? 1.15f : 1.35f;
|
||||
guny = ClampFloat(guny, -GUNAIMLIMIT, GUNAIMLIMIT);
|
||||
crosshairy = ClampFloat(crosshairy, -CROSSHAIRLIMIT, CROSSHAIRLIMIT);
|
||||
EMU_WriteFloat(playerbase[player] + PD_gunry, guny);
|
||||
EMU_WriteFloat(playerbase[player] + PD_gunryrecoil, crosshairy * (GUNRECOILYLIMIT / CROSSHAIRLIMIT));
|
||||
EMU_WriteFloat(playerbase[player] + PD_gunly, guny);
|
||||
EMU_WriteFloat(playerbase[player] + PD_gunlyrecoil, crosshairy * (GUNRECOILYLIMIT / CROSSHAIRLIMIT));
|
||||
EMU_WriteFloat(playerbase[player] + PD_crosshairy, crosshairy);
|
||||
}
|
||||
}
|
||||
}
|
||||
if(!dead && camera == 1 && !menu) // player is alive, in first person and is in menu
|
||||
PD_RadialMenuNav(player); // check if player is in radial menu and translate mouse input to C buttons
|
||||
else if(dead || camera != 1) // player is dead or not in first person camera
|
||||
{
|
||||
PD_ResetCrouchToggle(player); // reset crouch toggle
|
||||
PD_ResetCamspyStance(player); // reset camspy stance
|
||||
}
|
||||
}
|
||||
PD_Controller(); // set controller data
|
||||
}
|
||||
//==========================================================================
|
||||
// Purpose: crouching function for Perfect Dark (2 = stand, 1 = kneel, 0 = duck)
|
||||
// Changes Globals: safetocrouch, crouchstance, safetostand
|
||||
//==========================================================================
|
||||
static void PD_Crouch(const int player)
|
||||
{
|
||||
const int crouchheld = DEVICE[player].BUTTONPRIM[CROUCH] || DEVICE[player].BUTTONSEC[CROUCH];
|
||||
const int kneelheld = DEVICE[player].BUTTONPRIM[KNEEL] || DEVICE[player].BUTTONSEC[KNEEL];
|
||||
int stance = 2; // standing by default
|
||||
if(crouchheld)
|
||||
stance = 0;
|
||||
else if(kneelheld)
|
||||
stance = 1;
|
||||
if(PROFILE[player].SETTINGS[CROUCHTOGGLE]) // check and toggle player stance
|
||||
{
|
||||
const int crouchkneelheld = crouchheld || kneelheld; // holding down crouch/kneel
|
||||
if(safetocrouch[player] && crouchkneelheld) // stand to crouch/kneel
|
||||
safetocrouch[player] = 0, crouchstance[player] = crouchheld ? 0 : 1;
|
||||
else if(!safetocrouch[player] && !crouchkneelheld) // crouch/kneel is no longer being held, ready to stand
|
||||
safetostand[player] = 1;
|
||||
if(safetostand[player] && crouchkneelheld) // toggle to other stance
|
||||
{
|
||||
if(crouchheld && crouchstance[player] == 0 || kneelheld && crouchstance[player] == 1) // if pressed crouch/kneel twice, stand up
|
||||
safetocrouch[player] = 1, crouchstance[player] = 2;
|
||||
else
|
||||
safetostand[player] = 0, crouchstance[player] = crouchheld ? 0 : 1; // switch to the other crouch stance (kneel/crouch)
|
||||
}
|
||||
else if(safetostand[player] && safetocrouch[player] && !crouchkneelheld) // crouch/kneel key not active, ready to toggle
|
||||
safetostand[player] = 0;
|
||||
stance = crouchstance[player];
|
||||
}
|
||||
EMU_WriteInt(playerbase[player] + PD_stanceflag, stance); // set in-game stance
|
||||
}
|
||||
//==========================================================================
|
||||
// Purpose: replicate the original aiming system, uses aimx/y to move screen when crosshair is on border of screen
|
||||
// Changes Globals: crosshairposx, crosshairposy, gunrcenter, gunlcenter, aimx, aimy
|
||||
//==========================================================================
|
||||
static void PD_AimMode(const int player, const int aimingflag, const float fov, const float basefov)
|
||||
{
|
||||
const float crosshairx = EMU_ReadFloat(playerbase[player] + PD_crosshairx), crosshairy = EMU_ReadFloat(playerbase[player] + PD_crosshairy);
|
||||
const int gunrreload = EMU_ReadInt(playerbase[player] + PD_gunrstate) == 1, gunlreload = EMU_ReadInt(playerbase[player] + PD_gunlstate) == 1, unarmed = EMU_ReadInt(playerbase[player] + PD_currentweapon) < 2;
|
||||
const float fovratio = fov / basefov, fovmodifier = basefov / 60.f; // basefov is 60 unless override is above 60
|
||||
const float threshold = 0.72f, speed = 475.f, sensitivity = 100.f * fovmodifier, centertime = 60.f;
|
||||
if(aimingflag) // if player is aiming
|
||||
{
|
||||
const float mouseaccel = PROFILE[player].SETTINGS[ACCELERATION] ? sqrt(DEVICE[player].XPOS * DEVICE[player].XPOS + DEVICE[player].YPOS * DEVICE[player].YPOS) / TICKRATE / 12.0f * PROFILE[player].SETTINGS[ACCELERATION] : 0;
|
||||
crosshairposx[player] += DEVICE[player].XPOS / 10.0f * (PROFILE[player].SETTINGS[SENSITIVITY] / sensitivity / RATIOFACTOR) * fmax(mouseaccel, 1); // calculate the crosshair position
|
||||
crosshairposy[player] += (!PROFILE[player].SETTINGS[INVERTPITCH] ? DEVICE[player].YPOS : -DEVICE[player].YPOS) / 10.0f * (PROFILE[player].SETTINGS[SENSITIVITY] / sensitivity) * fmax(mouseaccel, 1);
|
||||
crosshairposx[player] = ClampFloat(crosshairposx[player], -CROSSHAIRLIMIT, CROSSHAIRLIMIT); // apply clamp then inject
|
||||
crosshairposy[player] = ClampFloat(crosshairposy[player], -CROSSHAIRLIMIT, CROSSHAIRLIMIT);
|
||||
EMU_WriteFloat(playerbase[player] + PD_crosshairx, crosshairposx[player]);
|
||||
EMU_WriteFloat(playerbase[player] + PD_crosshairy, crosshairposy[player]);
|
||||
if(unarmed || gunrreload) // if unarmed or reloading right weapon, remove from gunrcenter
|
||||
gunrcenter[player] -= emuoverclock ? 1 : 2;
|
||||
else if(gunrcenter[player] < (int)centertime) // increase gunrcenter over time until it equals centertime
|
||||
gunrcenter[player] += emuoverclock ? 1 : 2;
|
||||
if(gunlreload) // if reloading left weapon, remove from gunlcenter
|
||||
gunlcenter[player] -= emuoverclock ? 1 : 2;
|
||||
else if(gunlcenter[player] < (int)centertime)
|
||||
gunlcenter[player] += emuoverclock ? 1 : 2;
|
||||
if(gunrcenter[player] < 0)
|
||||
gunrcenter[player] = 0;
|
||||
if(gunlcenter[player] < 0)
|
||||
gunlcenter[player] = 0;
|
||||
EMU_WriteFloat(playerbase[player] + PD_gunrx, (gunrcenter[player] / centertime) * (crosshairposx[player] * 0.75f) + fovratio - 1); // calculate and inject the gun angles
|
||||
EMU_WriteFloat(playerbase[player] + PD_gunrxrecoil, crosshairposx[player] * (GUNRECOILXLIMIT / CROSSHAIRLIMIT) * fovmodifier * RATIOFACTOR); // set the recoil to the correct rotation (if we don't, then the recoil is always z axis aligned)
|
||||
EMU_WriteFloat(playerbase[player] + PD_gunry, (gunrcenter[player] / centertime) * (crosshairposy[player] * 0.66f) + fovratio - 1);
|
||||
EMU_WriteFloat(playerbase[player] + PD_gunryrecoil, crosshairposy[player] * (GUNRECOILYLIMIT / CROSSHAIRLIMIT) * fovmodifier);
|
||||
EMU_WriteFloat(playerbase[player] + PD_gunlx, (gunlcenter[player] / centertime) * (crosshairposx[player] * 0.75f) + fovratio - 1);
|
||||
EMU_WriteFloat(playerbase[player] + PD_gunlxrecoil, crosshairposx[player] * (GUNRECOILXLIMIT / CROSSHAIRLIMIT) * fovmodifier * RATIOFACTOR);
|
||||
EMU_WriteFloat(playerbase[player] + PD_gunly, (gunlcenter[player] / centertime) * (crosshairposy[player] * 0.66f) + fovratio - 1);
|
||||
EMU_WriteFloat(playerbase[player] + PD_gunlyrecoil, crosshairposy[player] * (GUNRECOILYLIMIT / CROSSHAIRLIMIT) * fovmodifier);
|
||||
if(crosshairx > 0 && crosshairx / CROSSHAIRLIMIT > threshold) // if crosshair is within threshold of the border then calculate a linear scrolling speed and enable mouselook
|
||||
aimx[player] = (crosshairx / CROSSHAIRLIMIT - threshold) * speed * TIMESTEP;
|
||||
else if(crosshairx < 0 && crosshairx / CROSSHAIRLIMIT < -threshold)
|
||||
aimx[player] = (crosshairx / CROSSHAIRLIMIT + threshold) * speed * TIMESTEP;
|
||||
else
|
||||
aimx[player] = 0;
|
||||
if(crosshairy > 0 && crosshairy / CROSSHAIRLIMIT > threshold)
|
||||
aimy[player] = (crosshairy / CROSSHAIRLIMIT - threshold) * speed * TIMESTEP;
|
||||
else if(crosshairy < 0 && crosshairy / CROSSHAIRLIMIT < -threshold)
|
||||
aimy[player] = (crosshairy / CROSSHAIRLIMIT + threshold) * speed * TIMESTEP;
|
||||
else
|
||||
aimy[player] = 0;
|
||||
}
|
||||
else // player is not aiming so reset crosshairposxy and gunrlcenter
|
||||
crosshairposx[player] = crosshairx, crosshairposy[player] = crosshairy, gunrcenter[player] = 0, gunlcenter[player] = 0;
|
||||
}
|
||||
//==========================================================================
|
||||
// Purpose: handle camspy/slayer controlling
|
||||
// Changes Globals: safetolowercamspy, camspystance, safetoraisecamspy, xstick, ystick, slayerairbrakes, usingstick
|
||||
//==========================================================================
|
||||
static void PD_CamspySlayer(const int player, const int camspyflag, const float sensitivity)
|
||||
{
|
||||
const int crouchheld = DEVICE[player].BUTTONPRIM[CROUCH] || DEVICE[player].BUTTONSEC[CROUCH] || DEVICE[player].BUTTONPRIM[KNEEL] || DEVICE[player].BUTTONSEC[KNEEL];
|
||||
if(camspyflag)
|
||||
{
|
||||
const unsigned int camspybase = (unsigned int)EMU_ReadInt(playerbase[player] + PD_camspybase);
|
||||
if(!WITHINRANGE(camspybase)) // if camspy pointer is invalid, abort
|
||||
return;
|
||||
const unsigned int camspyflag = (unsigned int)EMU_ReadInt(camspybase + PD_camspyflag) & 0x000000FF;
|
||||
if(!camspyflag) // if camspy active flag is false, abort
|
||||
return;
|
||||
float camspyx = EMU_ReadFloat(camspybase + PD_camspyx), camspyy = EMU_ReadFloat(camspybase + PD_camspyy);
|
||||
camspyx += DEVICE[player].XPOS / 10.0f * sensitivity; // regular mouselook calculation
|
||||
while(camspyx < 0)
|
||||
camspyx += 360;
|
||||
while(camspyx >= 360)
|
||||
camspyx -= 360;
|
||||
EMU_WriteFloat(camspybase + PD_camspyx, camspyx);
|
||||
if(camspyy > 90) // adjust minus range so clamping is easier to calculate
|
||||
camspyy -= 360;
|
||||
camspyy += (!PROFILE[player].SETTINGS[INVERTPITCH] ? -DEVICE[player].YPOS : DEVICE[player].YPOS) / 10.0f * (sensitivity / 1.5f); // slightly weaken y axis so camspy's fisheye effect isn't so sickening
|
||||
#ifdef SPEEDRUN_BUILD // allow full 180 degrees for speedrun build
|
||||
camspyy = ClampFloat(camspyy, -90, 90);
|
||||
#else
|
||||
camspyy = ClampFloat(camspyy, -75, 75); // limit range to usable field of view
|
||||
#endif
|
||||
if(camspyy < 0)
|
||||
camspyy += 360;
|
||||
EMU_WriteFloat(camspybase + PD_camspyy, camspyy);
|
||||
const float camspyycos = cosf(camspyy * (1.f * PI / 180.f)), camspyysin = sinf(camspyy * (1.f * PI / 180.f)); // update view matrix angles (engine only does this when necessary - so we manually update it every tick)
|
||||
EMU_WriteFloat(camspybase + PD_camspyycos, camspyycos);
|
||||
EMU_WriteFloat(camspybase + PD_camspyysin, camspyysin);
|
||||
if(safetolowercamspy[player] && crouchheld) // high to low
|
||||
safetolowercamspy[player] = 0, camspystance[player] = 1;
|
||||
else if(!safetolowercamspy[player] && !crouchheld) // crouch is no longer being held, ready to raise
|
||||
safetoraisecamspy[player] = 1;
|
||||
if(safetoraisecamspy[player] && crouchheld) // raise up
|
||||
safetolowercamspy[player] = 1, camspystance[player] = 0;
|
||||
else if(safetoraisecamspy[player] && safetolowercamspy[player] && !crouchheld) // crouch key not active, ready to toggle
|
||||
safetoraisecamspy[player] = 0;
|
||||
if(!DEVICE[player].BUTTONPRIM[AIM] && !DEVICE[player].BUTTONSEC[AIM]) // if not aiming, always adjust camspy height
|
||||
xstick[player] = camspystance[player] ? 64 : -64;
|
||||
else
|
||||
xstick[player] = 0;
|
||||
ystick[player] = 0;
|
||||
}
|
||||
else // slayer (does not use memory injection, otherwise handling would be too easy)
|
||||
{
|
||||
const float floatyness = 0.75f / TICKRATE;
|
||||
xstick[player] = (int)((!PROFILE[player].SETTINGS[INVERTPITCH] ? DEVICE[player].YPOS : -DEVICE[player].YPOS) * sensitivity * 17.0f + (xstick[player] * floatyness));
|
||||
ystick[player] = (int)((DEVICE[player].XPOS * sensitivity * 17.0f + (ystick[player] * floatyness)));
|
||||
slayerairbrakes[player] = crouchheld || DEVICE[player].BUTTONPRIM[BACKWARDS] || DEVICE[player].BUTTONSEC[BACKWARDS];
|
||||
}
|
||||
xstick[player] = ClampInt(xstick[player], -128, 127);
|
||||
ystick[player] = ClampInt(ystick[player], -128, 127);
|
||||
usingstick[player] = 1;
|
||||
}
|
||||
//==========================================================================
|
||||
// Purpose: translate mouse to weapon radial menu
|
||||
// Changes Globals: xmenu, ymenu, radialmenudirection
|
||||
//==========================================================================
|
||||
static void PD_RadialMenuNav(const int player)
|
||||
{
|
||||
const float max = 19, threshold = 13, diagonalthres = 0.75;
|
||||
if((DEVICE[player].BUTTONPRIM[ACCEPT] || DEVICE[player].BUTTONSEC[ACCEPT]) && !DEVICE[player].BUTTONPRIM[FIRE] && !DEVICE[player].BUTTONSEC[FIRE]) // if a button is held (reject if fire is pressed so aimx/y can be reset back to center)
|
||||
{
|
||||
xmenu[player] += DEVICE[player].XPOS / 10.0f * PROFILE[player].SETTINGS[SENSITIVITY] / 40.0f;
|
||||
ymenu[player] += DEVICE[player].YPOS / 10.0f * PROFILE[player].SETTINGS[SENSITIVITY] / 40.0f;
|
||||
xmenu[player] = ClampFloat(xmenu[player], -max, max);
|
||||
ymenu[player] = ClampFloat(ymenu[player], -max, max);
|
||||
if(ymenu[player] < -threshold) // c-up
|
||||
radialmenudirection[player][FORWARDS] = 1;
|
||||
else if(ymenu[player] > threshold) // c-down
|
||||
radialmenudirection[player][BACKWARDS] = 1;
|
||||
if(xmenu[player] < -threshold) // c-left
|
||||
radialmenudirection[player][STRAFELEFT] = 1;
|
||||
else if(xmenu[player] > threshold) // c-right
|
||||
radialmenudirection[player][STRAFERIGHT] = 1;
|
||||
if(xmenu[player] < -threshold && ymenu[player] < -threshold && (-xmenu[player] + -ymenu[player]) / (max * 2) > diagonalthres) // c-up-left
|
||||
radialmenudirection[player][FORWARDS] = 1, radialmenudirection[player][STRAFELEFT] = 1;
|
||||
else if(xmenu[player] > threshold && ymenu[player] < -threshold && (xmenu[player] + -ymenu[player]) / (max * 2) > diagonalthres) // c-up-right
|
||||
radialmenudirection[player][FORWARDS] = 1, radialmenudirection[player][STRAFERIGHT] = 1;
|
||||
else if(xmenu[player] < -threshold && ymenu[player] > threshold && (-xmenu[player] + ymenu[player]) / (max * 2) > diagonalthres) // c-down-left
|
||||
radialmenudirection[player][BACKWARDS] = 1, radialmenudirection[player][STRAFELEFT] = 1;
|
||||
else if(xmenu[player] > threshold && ymenu[player] > threshold && (xmenu[player] + ymenu[player]) / (max * 2) > diagonalthres) // c-down-right
|
||||
radialmenudirection[player][BACKWARDS] = 1, radialmenudirection[player][STRAFERIGHT] = 1;
|
||||
}
|
||||
else
|
||||
xmenu[player] = 0, ymenu[player] = 0;
|
||||
}
|
||||
//==========================================================================
|
||||
// Purpose: calculate and send emulator key combo
|
||||
// Changes Globals: xstick, ystick, usingstick, radialmenudirection
|
||||
//==========================================================================
|
||||
static void PD_Controller(void)
|
||||
{
|
||||
for(int player = PLAYER1; player < ALLPLAYERS; player++)
|
||||
{
|
||||
CONTROLLER[player].U_CBUTTON = DEVICE[player].BUTTONPRIM[FORWARDS] || DEVICE[player].BUTTONSEC[FORWARDS] || radialmenudirection[player][FORWARDS];
|
||||
CONTROLLER[player].D_CBUTTON = DEVICE[player].BUTTONPRIM[BACKWARDS] || DEVICE[player].BUTTONSEC[BACKWARDS] || radialmenudirection[player][BACKWARDS];
|
||||
CONTROLLER[player].L_CBUTTON = DEVICE[player].BUTTONPRIM[STRAFELEFT] || DEVICE[player].BUTTONSEC[STRAFELEFT] || radialmenudirection[player][STRAFELEFT];
|
||||
CONTROLLER[player].R_CBUTTON = DEVICE[player].BUTTONPRIM[STRAFERIGHT] || DEVICE[player].BUTTONSEC[STRAFERIGHT] || radialmenudirection[player][STRAFERIGHT];
|
||||
CONTROLLER[player].Z_TRIG = DEVICE[player].BUTTONPRIM[FIRE] || DEVICE[player].BUTTONSEC[FIRE] || DEVICE[player].BUTTONPRIM[PREVIOUSWEAPON] || DEVICE[player].BUTTONSEC[PREVIOUSWEAPON];
|
||||
CONTROLLER[player].R_TRIG = DEVICE[player].BUTTONPRIM[AIM] || DEVICE[player].BUTTONSEC[AIM];
|
||||
#ifndef SPEEDRUN_BUILD // speedrun build does not have reload button support
|
||||
CONTROLLER[player].RELOAD_HACK = DEVICE[player].BUTTONPRIM[RELOAD] || DEVICE[player].BUTTONSEC[RELOAD];
|
||||
#endif
|
||||
CONTROLLER[player].A_BUTTON = DEVICE[player].BUTTONPRIM[ACCEPT] || DEVICE[player].BUTTONSEC[ACCEPT] || DEVICE[player].BUTTONPRIM[PREVIOUSWEAPON] || DEVICE[player].BUTTONSEC[PREVIOUSWEAPON] || DEVICE[player].BUTTONPRIM[NEXTWEAPON] || DEVICE[player].BUTTONSEC[NEXTWEAPON];
|
||||
CONTROLLER[player].B_BUTTON = DEVICE[player].BUTTONPRIM[CANCEL] || DEVICE[player].BUTTONSEC[CANCEL];
|
||||
CONTROLLER[player].START_BUTTON = DEVICE[player].BUTTONPRIM[START] || DEVICE[player].BUTTONSEC[START];
|
||||
DEVICE[player].ARROW[0] = (DEVICE[player].BUTTONPRIM[UP] || DEVICE[player].BUTTONSEC[UP]) ? 127 : 0;
|
||||
DEVICE[player].ARROW[1] = (DEVICE[player].BUTTONPRIM[DOWN] || DEVICE[player].BUTTONSEC[DOWN]) ? -128 : 0;
|
||||
DEVICE[player].ARROW[2] = (DEVICE[player].BUTTONPRIM[LEFT] || DEVICE[player].BUTTONSEC[LEFT]) ? -128 : 0;
|
||||
DEVICE[player].ARROW[3] = (DEVICE[player].BUTTONPRIM[RIGHT] || DEVICE[player].BUTTONSEC[RIGHT]) ? 127 : 0;
|
||||
CONTROLLER[player].X_AXIS = DEVICE[player].ARROW[0] + DEVICE[player].ARROW[1];
|
||||
CONTROLLER[player].Y_AXIS = DEVICE[player].ARROW[2] + DEVICE[player].ARROW[3];
|
||||
if(usingstick[player]) // player is using camspy/slayer
|
||||
{
|
||||
if(xstick[player] != 0)
|
||||
CONTROLLER[player].X_AXIS = xstick[player];
|
||||
if(ystick[player] != 0)
|
||||
CONTROLLER[player].Y_AXIS = ystick[player];
|
||||
if(slayerairbrakes[player] != 0)
|
||||
CONTROLLER[player].R_TRIG = slayerairbrakes[player];
|
||||
usingstick[player] = 0;
|
||||
}
|
||||
else
|
||||
PD_ResetCamspySlayerStick(player); // reset x/y stick
|
||||
PD_ResetRadialMenuBtns(player); // reset radialmenudirection
|
||||
}
|
||||
}
|
||||
//==========================================================================
|
||||
// Purpose: inject hacks into rom before code has been cached
|
||||
//==========================================================================
|
||||
static void PD_InjectHacks(void)
|
||||
{
|
||||
const int addressarray[33] = {0x802C07B8, 0x802C07BC, 0x802C07EC, 0x802C07F0, 0x802C07FC, 0x802C0800, 0x802C0808, 0x802C0820, 0x802C0824, 0x802C082C, 0x802C0830, 0x803C7988, 0x803C798C, 0x803C7990, 0x803C7994, 0x803C7998, 0x803C799C, 0x803C79A0, 0x803C79A4, 0x803C79A8, 0x803C79AC, 0x803C79B0, 0x803C79B4, 0x803C79B8, 0x803C79BC, 0x803C79C0, 0x803C79C4, 0x803C79C8, 0x803C79CC, 0x803C79D0, 0x803C79D4, 0x803C79D8, 0x803C79DC}, codearray[33] = {0x0BC69E62, 0x8EA10120, 0x0BC69E67, 0x263107A4, 0x0BC69E6B, 0x4614C500, 0x46120682, 0x0BC69E6F, 0x26100004, 0x0BC69E73, 0x4614C500, 0x54200003, 0x00000000, 0xE6B21668, 0xE6A8166C, 0x0BC281F0, 0x8EA10120, 0x50200001, 0xE6380530, 0x0BC281FD, 0x8EA10120, 0x50200001, 0xE6340534, 0x0BC28201, 0x8EA10120, 0x50200001, 0xE6380530, 0x0BC2820A, 0x8EA10120, 0x50200001, 0xE6340534, 0x0BC2820D, 0x00000000}; // add branch to crosshair code so cursor aiming mode is absolute (without jitter)
|
||||
for(int index = 0; index < 33; index++) // inject code array
|
||||
EMU_WriteInt(addressarray[index], codearray[index]);
|
||||
if((unsigned int)EMU_ReadInt(PD_camspylookspringup) == 0xE4640028) // add code to remove look spring logic for camspy
|
||||
EMU_WriteInt(PD_camspylookspringup, 0x00000000); // replace instruction with nop
|
||||
if((unsigned int)EMU_ReadInt(PD_camspylookspringdown) == 0xE4680028) // add code to remove look spring logic for camspy
|
||||
EMU_WriteInt(PD_camspylookspringdown, 0x00000000); // replace instruction with nop
|
||||
#ifndef SPEEDRUN_BUILD // gives unfair advantage, remove for speedrun build
|
||||
const int reloadhack_address[22] = {0x8038A218, 0x8038A21C, 0x8038A228, 0x8038A22C, 0x8038A230, 0x8038A234, 0x8038A238, 0x8038A23C, 0x8038A240, 0x8038A244, 0x8038A248, 0x8038A24C, 0x8038A250, 0x8038A254, 0x8038A258, 0x8038A25C, 0x8038A268, 0x8038A270, 0x803C79E0, 0x803C79E4, 0x803C79E8, 0x803C79EC}, reloadhack_code[22] = {0x13000003, 0x00000000, 0x8E020480, 0x5440000B, 0x804C0037, 0x3C04800A, 0x8C84A24C, 0x0C005408, 0x34050040, 0x1040000B, 0x00000000, 0x0FC28886, 0x00002025, 0x0BC69E78, 0x00000000, 0x1180FFF5, 0x00000000, 0x34040001, 0x0FC28886, 0x34040001, 0x0BC5A89D, 0x00000000}; // add reload button hack
|
||||
for(int index = 0; index < 22; index++) // inject code array
|
||||
EMU_WriteInt(reloadhack_address[index], reloadhack_code[index]);
|
||||
if((unsigned int)EMU_ReadInt(PD_controlstyle) == 0x9042C7FC) // if safe to overwrite
|
||||
EMU_WriteInt(PD_controlstyle, 0x34020001); // always force game to use 1.2 control style
|
||||
if((unsigned int)EMU_ReadInt(PD_reversepitch) == 0x000F102B) // if safe to overwrite
|
||||
EMU_WriteInt(PD_reversepitch, 0x34020001); // always force game to use upright pitch
|
||||
if((unsigned int)EMU_ReadInt(PD_pickupyaxisthreshold) == 0xBF4907A9) // if safe to overwrite
|
||||
EMU_WriteFloat(PD_pickupyaxisthreshold, -60.f * PI / 180.f); // overwrite default y axis limit for picking up items (from -45 to -60)
|
||||
if((unsigned int)EMU_ReadInt(PD_radialmenutimer) == 0x28410010 && emuoverclock) // make radial menu trigger quicker (from 15 to 8 ticks)
|
||||
EMU_WriteInt(PD_radialmenutimer, 0x28410009);
|
||||
if((unsigned int)EMU_ReadInt(PD_radialmenualphainit) == 0x3E99999A) // make radial menus initialize with 75% alpha
|
||||
EMU_WriteFloat(PD_radialmenualphainit, 0.75f);
|
||||
if((unsigned int)EMU_ReadInt(PD_blurfix) == 0x00000000) // add code to clear blur value on death
|
||||
EMU_WriteInt(PD_blurfix, 0xA46002D8); // replace nop with sh $r0, 0x02D8 ($v1)
|
||||
if((unsigned int)EMU_ReadInt(PD_hiresoption) == 0x24040001) // disable hires mode due (only benefits console/LLE plugins which are unsupported by 1964)
|
||||
EMU_WriteInt(PD_hiresoption, 0x24040000); // always set to false
|
||||
if(OVERRIDEFOV != 60) // override default fov
|
||||
{
|
||||
float newfov = OVERRIDEFOV;
|
||||
unsigned int unsignedinteger = *(unsigned int *)(float *)(&newfov);
|
||||
EMU_WriteInt(PD_defaultfov, 0x3C010000 + (short)(unsignedinteger / 0x10000));
|
||||
EMU_WriteInt(PD_defaultfovzoom, 0x3C010000 + (short)(unsignedinteger / 0x10000));
|
||||
if(!bypassviewmodelfovtweak) // allow user to bypass viewmodel position compensation for override fov (so they can see more detail at the expense of displaying animation culling keyframes)
|
||||
{
|
||||
if((unsigned int)EMU_ReadInt(EMU_ReadInt(PD_weapontable) + 0x30) == 0xC2240000) // if first weapon slot position is default
|
||||
{
|
||||
for(int index = 0; index < 64; index++) // cycle through first 64 weapons
|
||||
{
|
||||
const unsigned int weaponptr = EMU_ReadInt(PD_weapontable + (index * 4)); // get pointer for weapon slot
|
||||
const float fovoffset = OVERRIDEFOV - 60;
|
||||
const float weaponypos = EMU_ReadFloat(weaponptr + 0x30) - (fovoffset / (2.75f * 4.f)); // adjust weapon Y/Z positions for override field of view
|
||||
const float weaponzpos = EMU_ReadFloat(weaponptr + 0x34) + (fovoffset / 3.f);
|
||||
EMU_WriteFloat(weaponptr + 0x30, weaponypos);
|
||||
EMU_WriteFloat(weaponptr + 0x34, weaponzpos);
|
||||
}
|
||||
}
|
||||
}
|
||||
if(OVERRIDEFOV > 60)
|
||||
{
|
||||
newfov = 15.f / (OVERRIDEFOV / 60.f);
|
||||
unsignedinteger = *(unsigned int *)(float *)(&newfov);
|
||||
EMU_WriteInt(PD_defaultzoominspeed, 0x3C010000 + (short)(unsignedinteger / 0x10000)); // adjust zoom in speed default (15.f)
|
||||
newfov = 30.f * (OVERRIDEFOV / 60.f);
|
||||
unsignedinteger = *(unsigned int *)(float *)(&newfov);
|
||||
EMU_WriteInt(PD_defaultzoomoutspeed, 0x3C010000 + (short)(unsignedinteger / 0x10000)); // adjust zoom out speed default (30.f)
|
||||
}
|
||||
}
|
||||
if((unsigned int)EMU_ReadInt(PD_defaultratio) == 0x3FAAAAAB && (overrideratiowidth != 16 || overrideratioheight != 9)) // override default 16:9 ratio
|
||||
EMU_WriteFloat(PD_defaultratio, ((float)overrideratiowidth / (float)overrideratioheight) / (4.f / 3.f));
|
||||
#endif
|
||||
if(CONTROLLER[PLAYER1].Z_TRIG && CONTROLLER[PLAYER1].R_TRIG) // skip intros if holding down fire + aim
|
||||
EMU_WriteInt(PD_introcounter, 0x00001000);
|
||||
}
|
||||
//==========================================================================
|
||||
// Purpose: run when emulator closes rom
|
||||
// Changes Globals: playerbase, safetocrouch, safetostand, crouchstance, xmenu, ymenu
|
||||
//==========================================================================
|
||||
void PD_Quit(void)
|
||||
{
|
||||
for(int player = PLAYER1; player < ALLPLAYERS; player++)
|
||||
{
|
||||
playerbase[player] = 0;
|
||||
PD_ResetCrouchToggle(player);
|
||||
PD_ResetCamspyStance(player);
|
||||
xmenu[player] = 0, ymenu[player] = 0;
|
||||
}
|
||||
}
|
||||
@@ -1,130 +0,0 @@
|
||||
//==========================================================================
|
||||
// Mouse Injector Plugin
|
||||
//==========================================================================
|
||||
// Copyright (C) 2016-2021 Carnivorous
|
||||
// All rights reserved.
|
||||
//
|
||||
// Mouse Injector 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, visit http://www.gnu.org/licenses/gpl-2.0.html
|
||||
//==========================================================================
|
||||
#define __MOUSE_INJECTOR_VERSION__ "V2.3"
|
||||
#define __CURRENTYEAR__ "2021"
|
||||
#define CONSOLE { AllocConsole(); AttachConsole(GetCurrentProcessId()); freopen("CON", "w", stdout); }
|
||||
#define ONLY1PLAYERACTIVE \
|
||||
(PROFILE[PLAYER1].SETTINGS[CONFIG] != DISABLED && PROFILE[PLAYER2].SETTINGS[CONFIG] == DISABLED && PROFILE[PLAYER3].SETTINGS[CONFIG] == DISABLED && PROFILE[PLAYER4].SETTINGS[CONFIG] == DISABLED || \
|
||||
PROFILE[PLAYER1].SETTINGS[CONFIG] == DISABLED && PROFILE[PLAYER2].SETTINGS[CONFIG] != DISABLED && PROFILE[PLAYER3].SETTINGS[CONFIG] == DISABLED && PROFILE[PLAYER4].SETTINGS[CONFIG] == DISABLED || \
|
||||
PROFILE[PLAYER1].SETTINGS[CONFIG] == DISABLED && PROFILE[PLAYER2].SETTINGS[CONFIG] == DISABLED && PROFILE[PLAYER3].SETTINGS[CONFIG] != DISABLED && PROFILE[PLAYER4].SETTINGS[CONFIG] == DISABLED || \
|
||||
PROFILE[PLAYER1].SETTINGS[CONFIG] == DISABLED && PROFILE[PLAYER2].SETTINGS[CONFIG] == DISABLED && PROFILE[PLAYER3].SETTINGS[CONFIG] == DISABLED && PROFILE[PLAYER4].SETTINGS[CONFIG] != DISABLED)
|
||||
#if _MSC_VER && !__INTEL_COMPILER // here because some MSVC versions only support __inline :/
|
||||
#define inline __inline
|
||||
#endif
|
||||
#define FOV_MIN 40
|
||||
#define FOV_MAX 120
|
||||
#define ARRAY_SIZE(array) ((size_t)(sizeof(array)/sizeof(*array)))
|
||||
|
||||
inline float ClampFloat(const float value, const float min, const float max)
|
||||
{
|
||||
const float test = value < min ? min : value;
|
||||
return test > max ? max : test;
|
||||
}
|
||||
|
||||
inline int ClampInt(const int value, const int min, const int max)
|
||||
{
|
||||
const int test = value < min ? min : value;
|
||||
return test > max ? max : test;
|
||||
}
|
||||
|
||||
// profile struct
|
||||
enum CONTROLLERENUM {FORWARDS = 0, BACKWARDS, STRAFELEFT, STRAFERIGHT, FIRE, AIM, RELOAD, ACCEPT, CANCEL, START, CROUCH, KNEEL, PREVIOUSWEAPON, NEXTWEAPON, UP, DOWN, LEFT, RIGHT, TOTALBUTTONS};
|
||||
enum CONFIGENUM {CONFIG = 0, SENSITIVITY, ACCELERATION, CROSSHAIR, INVERTPITCH, CROUCHTOGGLE, GEAIMMODE, PDAIMMODE, MOUSE, KEYBOARD, TOTALSETTINGS};
|
||||
enum QUICKCONFIGENUM {DISABLED = 0, WASD, ESDF, CUSTOM};
|
||||
enum PLAYERSENUM {PLAYER1 = 0, PLAYER2, PLAYER3, PLAYER4, ALLPLAYERS};
|
||||
enum DEVICETYPE {MOUSETYPE = 0, KEYBOARDTYPE};
|
||||
|
||||
struct PROFILE_STRUCT
|
||||
{
|
||||
int BUTTONPRIM[TOTALBUTTONS];
|
||||
int BUTTONSEC[TOTALBUTTONS];
|
||||
int SETTINGS[TOTALSETTINGS];
|
||||
};
|
||||
|
||||
// device struct (used for all game input)
|
||||
struct DEVICE_STRUCT
|
||||
{
|
||||
int XPOS, YPOS; // mouse input
|
||||
int WHEEL; // mouse wheel buffer cool down
|
||||
int BUTTONPRIM[TOTALBUTTONS]; // button values for primary set (0-1)
|
||||
int BUTTONSEC[TOTALBUTTONS]; // button values for secondary set (0-1)
|
||||
int ARROW[4]; // arrow information
|
||||
};
|
||||
|
||||
// plugin spec
|
||||
#define PLUGIN_TYPE_CONTROLLER 4
|
||||
|
||||
#define PLUGIN_NONE 1
|
||||
#define PLUGIN_MEMPAK 2
|
||||
#define PLUGIN_RUMBLE_PAK 3 // not implemented for non raw data
|
||||
#define PLUGIN_TANSFER_PAK 4 // not implemented for non raw data
|
||||
|
||||
// Structures (Note: BOOL, WORD, DWORD, HWND are defined in windows.h)
|
||||
#ifndef _WINDOWS_
|
||||
typedef unsigned short WORD;
|
||||
typedef int BOOL;
|
||||
typedef unsigned long DWORD;
|
||||
typedef void *HWND;
|
||||
#endif
|
||||
|
||||
typedef struct
|
||||
{
|
||||
WORD Version; // Should be set to 0xFBAD
|
||||
WORD Type; // Set to PLUGIN_TYPE_CONTROLLER
|
||||
char Name[100]; // Name of the DLL
|
||||
BOOL Reserved1;
|
||||
BOOL Reserved2;
|
||||
} PLUGIN_INFO;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
BOOL Present;
|
||||
BOOL RawData;
|
||||
int Plugin;
|
||||
} CONTROL;
|
||||
|
||||
typedef union
|
||||
{
|
||||
DWORD Value;
|
||||
struct
|
||||
{
|
||||
unsigned R_DPAD: 1;
|
||||
unsigned L_DPAD: 1;
|
||||
unsigned D_DPAD: 1;
|
||||
unsigned U_DPAD: 1;
|
||||
unsigned START_BUTTON: 1;
|
||||
unsigned Z_TRIG: 1;
|
||||
unsigned B_BUTTON: 1;
|
||||
unsigned A_BUTTON: 1;
|
||||
|
||||
unsigned R_CBUTTON: 1;
|
||||
unsigned L_CBUTTON: 1;
|
||||
unsigned D_CBUTTON: 1;
|
||||
unsigned U_CBUTTON: 1;
|
||||
unsigned R_TRIG: 1;
|
||||
unsigned L_TRIG: 1;
|
||||
unsigned RELOAD_HACK: 1; // this unused button is reused as a hacked reload button
|
||||
unsigned RESERVED: 1;
|
||||
|
||||
signed Y_AXIS: 8;
|
||||
|
||||
signed X_AXIS: 8;
|
||||
};
|
||||
} BUTTONS;
|
||||
File diff suppressed because it is too large.
Load diff
@@ -1,49 +0,0 @@
|
||||
//==========================================================================
|
||||
// Mouse Injector Plugin
|
||||
//==========================================================================
|
||||
// Copyright (C) 2016-2021 Carnivorous
|
||||
// All rights reserved.
|
||||
//
|
||||
// Mouse Injector 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, visit http://www.gnu.org/licenses/gpl-2.0.html
|
||||
//==========================================================================
|
||||
#define TICKRATE_OC 2 // 2ms (500 Hz) for overclocked
|
||||
#define TICKRATE_STOCK 4 // 4ms (250 Hz) for stock speed
|
||||
#define TICKRATE (emuoverclock ? TICKRATE_OC : TICKRATE_STOCK)
|
||||
#define TIMESTEP TICKRATE / 1000
|
||||
#ifdef SPEEDRUN_BUILD // fov/ratio hacks gives unfair advantage, always use default values for speedrun build
|
||||
#define RATIOFACTOR 1.f
|
||||
#define OVERRIDEFOV 60
|
||||
#else
|
||||
#define RATIOFACTOR (((float)overrideratiowidth / (float)overrideratioheight) / (16.f / 9.f))
|
||||
#define OVERRIDEFOV overridefov
|
||||
#endif
|
||||
|
||||
extern BUTTONS CONTROLLER[4];
|
||||
extern struct PROFILE_STRUCT PROFILE[4];
|
||||
extern struct DEVICE_STRUCT DEVICE[4];
|
||||
|
||||
extern const unsigned char **rdramptr;
|
||||
extern const unsigned char **romptr;
|
||||
extern int stopthread;
|
||||
extern int mousetogglekey;
|
||||
extern int mousetoggle;
|
||||
extern int mouselockonfocus;
|
||||
extern int mouseunlockonloss;
|
||||
extern int configdialogopen;
|
||||
extern HWND emulatorwindow;
|
||||
extern int emuoverclock;
|
||||
extern int overridefov;
|
||||
extern int overrideratiowidth, overrideratioheight;
|
||||
extern int geshowcrosshair;
|
||||
extern int bypassviewmodelfovtweak;
|
||||
@@ -1,76 +0,0 @@
|
||||
#Mouse Injector Makefile
|
||||
#Use with TDM-GCC 4.9.2-tdm-3 or MinGW
|
||||
#For portable MinGW download Orwell Dev-C++
|
||||
#mingw32-make.exe -f makefile to compile
|
||||
|
||||
#Compiler directories
|
||||
MINGWDIR = C:/MinGW64/bin/
|
||||
CC = $(MINGWDIR)gcc
|
||||
WINDRES = $(MINGWDIR)windres
|
||||
|
||||
#Source directories
|
||||
SRCDIR = ./
|
||||
MANYMOUSEDIR = $(SRCDIR)manymouse/
|
||||
GAMESDIR = $(SRCDIR)games/
|
||||
OBJDIR = $(SRCDIR)obj/
|
||||
UIDIR = $(SRCDIR)ui/
|
||||
DLLNAME = $(SRCDIR)Mouse_Injector.dll
|
||||
|
||||
#Compiler flags
|
||||
#USE_DISCORD_PRESENCE = uncomment line to add discord rich presence (requires clean and rebuild)
|
||||
#SPEEDRUN_BUILD = uncomment line to build speedrun version (requires clean and rebuild)
|
||||
CFLAGS = -ansi -O2 -m32 -std=c11 -Wall
|
||||
ifdef USE_DISCORD_PRESENCE
|
||||
CFLAGS += -DADD_DISCORD_PRESENCE
|
||||
endif
|
||||
ifdef SPEEDRUN_BUILD
|
||||
CFLAGS += -DSPEEDRUN_BUILD
|
||||
DLLNAME = $(SRCDIR)Mouse_Injector_Speedrun.dll
|
||||
endif
|
||||
WARNINGS = -Wextra -pedantic -Wunreachable-code -Wno-parentheses -Wno-strict-aliasing
|
||||
RESFLAGS = -F pe-i386 --input-format=rc -O coff
|
||||
|
||||
#Linker flags
|
||||
OBJS = $(OBJDIR)maindll.o $(OBJDIR)device.o $(OBJDIR)discord.o $(OBJDIR)manymouse.o $(OBJDIR)windows_wminput.o $(OBJDIR)game.o $(OBJDIR)goldeneye.o $(OBJDIR)perfectdark.o $(OBJDIR)ui.res
|
||||
LIBS = -static-libgcc
|
||||
ifdef USE_DISCORD_PRESENCE
|
||||
LIBS += -L./discord -ldiscord-rpc
|
||||
endif
|
||||
LFLAGS = -shared $(OBJS) -o $(DLLNAME) $(LIBS) -m32 -s -Wl,--add-stdcall-alias
|
||||
|
||||
#Main recipes
|
||||
mouseinjector: $(OBJS)
|
||||
$(CC) $(LFLAGS)
|
||||
|
||||
all: clean mouseinjector
|
||||
|
||||
#Individual recipes
|
||||
$(OBJDIR)maindll.o: $(SRCDIR)maindll.c $(SRCDIR)global.h $(SRCDIR)maindll.h $(SRCDIR)device.h $(SRCDIR)discord.h $(UIDIR)ui.rc $(UIDIR)resource.h $(SRCDIR)vkey.h
|
||||
$(CC) -c $(SRCDIR)maindll.c -o $(OBJDIR)maindll.o $(CFLAGS) $(WARNINGS) -Wno-unused-parameter
|
||||
|
||||
$(OBJDIR)device.o: $(SRCDIR)device.c $(SRCDIR)global.h $(SRCDIR)device.h $(SRCDIR)maindll.h $(MANYMOUSEDIR)manymouse.h $(GAMESDIR)game.h
|
||||
$(CC) -c $(SRCDIR)device.c -o $(OBJDIR)device.o $(CFLAGS) $(WARNINGS)
|
||||
|
||||
$(OBJDIR)discord.o: $(SRCDIR)discord.c $(SRCDIR)global.h $(SRCDIR)discord.h $(SRCDIR)maindll.h $(GAMESDIR)game.h $(GAMESDIR)memory.h
|
||||
$(CC) -c $(SRCDIR)discord.c -o $(OBJDIR)discord.o $(CFLAGS) $(WARNINGS)
|
||||
|
||||
$(OBJDIR)manymouse.o: $(MANYMOUSEDIR)manymouse.c $(MANYMOUSEDIR)manymouse.h
|
||||
$(CC) -c $(MANYMOUSEDIR)manymouse.c -o $(OBJDIR)manymouse.o $(CFLAGS) $(WARNINGS)
|
||||
|
||||
$(OBJDIR)windows_wminput.o: $(MANYMOUSEDIR)windows_wminput.c $(MANYMOUSEDIR)manymouse.h
|
||||
$(CC) -c $(MANYMOUSEDIR)windows_wminput.c -o $(OBJDIR)windows_wminput.o $(CFLAGS)
|
||||
|
||||
$(OBJDIR)game.o: $(GAMESDIR)game.c $(GAMESDIR)game.h
|
||||
$(CC) -c $(GAMESDIR)game.c -o $(OBJDIR)game.o $(CFLAGS) $(WARNINGS)
|
||||
|
||||
$(OBJDIR)goldeneye.o: $(GAMESDIR)goldeneye.c $(SRCDIR)global.h $(SRCDIR)device.h $(SRCDIR)maindll.h $(GAMESDIR)game.h $(GAMESDIR)memory.h
|
||||
$(CC) -c $(GAMESDIR)goldeneye.c -o $(OBJDIR)goldeneye.o $(CFLAGS) $(WARNINGS)
|
||||
|
||||
$(OBJDIR)perfectdark.o: $(GAMESDIR)perfectdark.c $(SRCDIR)global.h $(SRCDIR)device.h $(SRCDIR)maindll.h $(GAMESDIR)game.h $(GAMESDIR)memory.h
|
||||
$(CC) -c $(GAMESDIR)perfectdark.c -o $(OBJDIR)perfectdark.o $(CFLAGS) $(WARNINGS)
|
||||
|
||||
$(OBJDIR)ui.res: $(UIDIR)ui.rc $(UIDIR)resource.h
|
||||
$(WINDRES) -i $(UIDIR)ui.rc -o $(OBJDIR)ui.res $(RESFLAGS)
|
||||
|
||||
clean:
|
||||
rm -f $(SRCDIR)*.dll $(OBJDIR)*.o $(OBJDIR)*.res
|
||||
@@ -1,23 +0,0 @@
|
||||
|
||||
Copyright (c) 2005-2012 Ryan C. Gordon and others.
|
||||
|
||||
This software is provided 'as-is', without any express or implied warranty.
|
||||
In no event will the authors be held liable for any damages arising from
|
||||
the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software in a
|
||||
product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||
Ryan C. Gordon <icculus@icculus.org>
|
||||
|
||||
@@ -1,92 +0,0 @@
|
||||
/*
|
||||
* ManyMouse foundation code; apps talks to this and it talks to the lowlevel
|
||||
* code for various platforms.
|
||||
*
|
||||
* Please see the file LICENSE.txt in the source's root directory.
|
||||
*
|
||||
* This file written by Ryan C. Gordon.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "manymouse.h"
|
||||
|
||||
static const char *manymouse_copyright =
|
||||
"ManyMouse " MANYMOUSE_VERSION " copyright (c) 2005-2012 Ryan C. Gordon.";
|
||||
|
||||
extern const ManyMouseDriver *ManyMouseDriver_windows;
|
||||
|
||||
/*
|
||||
* These have to be in the favored order...obviously it doesn't matter if the
|
||||
* Linux driver comes before or after the Windows one, since one won't
|
||||
* exist on a given platform, but things like Mac OS X's hidmanager (which
|
||||
* only works on OS X 10.5 and later) should come before Mac OS X's
|
||||
* hidutilities (which works on older systems, but may stop working in 10.6
|
||||
* and later). In the Mac OS X case, you want to try the newer tech, and if
|
||||
* it's not available (on 10.4 or earlier), fall back to trying the legacy
|
||||
* code.
|
||||
*/
|
||||
static const ManyMouseDriver **mice_drivers[] =
|
||||
{
|
||||
&ManyMouseDriver_windows,
|
||||
};
|
||||
|
||||
|
||||
static const ManyMouseDriver *driver = NULL;
|
||||
|
||||
int ManyMouse_Init(void)
|
||||
{
|
||||
const int upper = (sizeof (mice_drivers) / sizeof (mice_drivers[0]));
|
||||
int i;
|
||||
int retval = -1;
|
||||
|
||||
/* impossible test to keep manymouse_copyright linked into the binary. */
|
||||
if (manymouse_copyright == NULL)
|
||||
return -1;
|
||||
|
||||
if (driver != NULL)
|
||||
return -1;
|
||||
|
||||
for (i = 0; (i < upper) && (driver == NULL); i++)
|
||||
{
|
||||
const ManyMouseDriver *this_driver = *(mice_drivers[i]);
|
||||
if (this_driver != NULL) /* if not built for this platform, skip it. */
|
||||
{
|
||||
const int mice = this_driver->init();
|
||||
if (mice > retval)
|
||||
retval = mice; /* may move from "error" to "no mice found". */
|
||||
|
||||
if (mice >= 0)
|
||||
driver = this_driver;
|
||||
} /* if */
|
||||
} /* for */
|
||||
|
||||
return retval;
|
||||
} /* ManyMouse_Init */
|
||||
|
||||
|
||||
void ManyMouse_Quit(void)
|
||||
{
|
||||
if (driver != NULL)
|
||||
{
|
||||
driver->quit();
|
||||
driver = NULL;
|
||||
} /* if */
|
||||
} /* ManyMouse_Quit */
|
||||
|
||||
const char *ManyMouse_DriverName(void)
|
||||
{
|
||||
return (driver) ? driver->driver_name : NULL;
|
||||
} /* ManyMouse_DriverName */
|
||||
|
||||
const char *ManyMouse_DeviceName(unsigned int index, unsigned int iskeyboard)
|
||||
{
|
||||
return (driver) ? driver->name(index, iskeyboard) : NULL;
|
||||
} /* ManyMouse_DeviceName */
|
||||
|
||||
int ManyMouse_PollEvent(ManyMouseEvent *event)
|
||||
{
|
||||
return (driver) ? driver->poll(event) : 0;
|
||||
} /* ManyMouse_PollEvent */
|
||||
|
||||
/* end of manymouse.c ... */
|
||||
|
||||
@@ -1,65 +0,0 @@
|
||||
/*
|
||||
* ManyMouse main header. Include this from your app.
|
||||
*
|
||||
* Please see the file LICENSE.txt in the source's root directory.
|
||||
*
|
||||
* This file written by Ryan C. Gordon.
|
||||
*/
|
||||
|
||||
#ifndef _INCLUDE_MANYMOUSE_H_
|
||||
#define _INCLUDE_MANYMOUSE_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define MANYMOUSE_VERSION "0.0.3"
|
||||
|
||||
typedef enum
|
||||
{
|
||||
MANYMOUSE_EVENT_ABSMOTION = 0,
|
||||
MANYMOUSE_EVENT_RELMOTION,
|
||||
MANYMOUSE_EVENT_BUTTON,
|
||||
MANYMOUSE_EVENT_SCROLL,
|
||||
MANYMOUSE_EVENT_KEYBOARD,
|
||||
MANYMOUSE_EVENT_DISCONNECT,
|
||||
MANYMOUSE_EVENT_MAX
|
||||
} ManyMouseEventType;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
ManyMouseEventType type;
|
||||
unsigned int device;
|
||||
unsigned int item;
|
||||
int value;
|
||||
int minval;
|
||||
int maxval;
|
||||
unsigned int iskeyboard;
|
||||
} ManyMouseEvent;
|
||||
|
||||
|
||||
/* internal use only. */
|
||||
typedef struct
|
||||
{
|
||||
const char *driver_name;
|
||||
int (*init)(void);
|
||||
void (*quit)(void);
|
||||
const char *(*name)(unsigned int index, unsigned int iskeyboard);
|
||||
int (*poll)(ManyMouseEvent *event);
|
||||
} ManyMouseDriver;
|
||||
|
||||
|
||||
int ManyMouse_Init(void);
|
||||
const char *ManyMouse_DriverName(void);
|
||||
void ManyMouse_Quit(void);
|
||||
const char *ManyMouse_DeviceName(unsigned int index, unsigned int iskeyboard);
|
||||
int ManyMouse_PollEvent(ManyMouseEvent *event);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* !defined _INCLUDE_MANYMOUSE_H_ */
|
||||
|
||||
/* end of manymouse.h ... */
|
||||
|
||||
@@ -1,758 +0,0 @@
|
||||
/*
|
||||
* Support for Windows via the WM_INPUT message.
|
||||
*
|
||||
* Please see the file LICENSE.txt in the source's root directory.
|
||||
*
|
||||
* This file written by Ryan C. Gordon.
|
||||
*/
|
||||
|
||||
#include "manymouse.h"
|
||||
|
||||
#if (defined(_WIN32) || defined(_WINDOWS) || defined(__CYGWIN__))
|
||||
|
||||
/* WinUser.h won't include rawinput stuff without this... */
|
||||
#if (_WIN32_WINNT < 0x0501)
|
||||
#undef _WIN32_WINNT
|
||||
#define _WIN32_WINNT 0x0501
|
||||
#endif
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN 1
|
||||
#include <windows.h>
|
||||
#include <setupapi.h>
|
||||
#include <malloc.h> /* needed for alloca(). */
|
||||
|
||||
/* Cygwin's headers don't have WM_INPUT right now... */
|
||||
#ifndef WM_INPUT
|
||||
#define WM_INPUT 0x00FF
|
||||
#endif
|
||||
|
||||
/* that should be enough, knock on wood. */
|
||||
#define MAX_MICE 32
|
||||
|
||||
/*
|
||||
* Just trying to avoid malloc() here...we statically allocate a buffer
|
||||
* for events and treat it as a ring buffer.
|
||||
*/
|
||||
/* !!! FIXME: tweak this? */
|
||||
#define MAX_EVENTS 1024
|
||||
static ManyMouseEvent input_events[MAX_EVENTS];
|
||||
static volatile int input_events_read = 0;
|
||||
static volatile int input_events_write = 0;
|
||||
static int available_devices = 0;
|
||||
static int did_api_lookup = 0;
|
||||
static HWND raw_hwnd = NULL;
|
||||
static const char *class_name = "ManyMouseRawInputCatcher";
|
||||
static const char *win_name = "ManyMouseRawInputMsgWindow";
|
||||
static ATOM class_atom = 0;
|
||||
static CRITICAL_SECTION mutex;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
HANDLE handle;
|
||||
UINT iskeyboard;
|
||||
char name[256];
|
||||
} MouseStruct;
|
||||
static MouseStruct mice[MAX_MICE];
|
||||
|
||||
|
||||
/*
|
||||
* The RawInput APIs only exist in Windows XP and later, so you want this
|
||||
* to fail gracefully on earlier systems instead of refusing to start the
|
||||
* process due to missing symbols. To this end, we do a symbol lookup on
|
||||
* User32.dll, etc to get the entry points.
|
||||
*
|
||||
* A lot of these are available all the way back to the start of win32 in
|
||||
* Windows 95 and WinNT 3.1, but just so you don't have to track down any
|
||||
* import libraries, I've added those here, too. That fits well with the
|
||||
* idea of just adding the sources to your build and going forward.
|
||||
*/
|
||||
static UINT (WINAPI *pGetRawInputDeviceList)(PRAWINPUTDEVICELIST,PUINT,UINT);
|
||||
/* !!! FIXME: use unicode version */
|
||||
static UINT (WINAPI *pGetRawInputDeviceInfoA)(HANDLE,UINT,LPVOID,PUINT);
|
||||
static BOOL (WINAPI *pRegisterRawInputDevices)(PCRAWINPUTDEVICE,UINT,UINT);
|
||||
static LRESULT (WINAPI *pDefRawInputProc)(PRAWINPUT *,INT,UINT);
|
||||
static UINT (WINAPI *pGetRawInputBuffer)(PRAWINPUT,PUINT,UINT);
|
||||
static UINT (WINAPI *pGetRawInputData)(HRAWINPUT,UINT,LPVOID,PUINT,UINT);
|
||||
static HWND (WINAPI *pCreateWindowExA)(DWORD,LPCTSTR,LPCTSTR,DWORD,int,int,int,int,HWND,HMENU,HINSTANCE,LPVOID);
|
||||
static ATOM (WINAPI *pRegisterClassExA)(CONST WNDCLASSEX *);
|
||||
static LRESULT (WINAPI *pDefWindowProcA)(HWND,UINT,WPARAM,LPARAM);
|
||||
static BOOL (WINAPI *pUnregisterClassA)(LPCTSTR,HINSTANCE);
|
||||
static HMODULE (WINAPI *pGetModuleHandleA)(LPCTSTR);
|
||||
static BOOL (WINAPI *pPeekMessageA)(LPMSG,HWND,UINT,UINT,UINT);
|
||||
static BOOL (WINAPI *pTranslateMessage)(const MSG *);
|
||||
static LRESULT (WINAPI *pDispatchMessageA)(const MSG *);
|
||||
static BOOL (WINAPI *pDestroyWindow)(HWND);
|
||||
static void (WINAPI *pInitializeCriticalSection)(LPCRITICAL_SECTION);
|
||||
static void (WINAPI *pEnterCriticalSection)(LPCRITICAL_SECTION);
|
||||
static void (WINAPI *pLeaveCriticalSection)(LPCRITICAL_SECTION);
|
||||
static void (WINAPI *pDeleteCriticalSection)(LPCRITICAL_SECTION);
|
||||
static DWORD (WINAPI *pGetLastError)(void);
|
||||
static HDEVINFO (WINAPI *pSetupDiGetClassDevsA)(LPGUID, LPCTSTR, HWND, DWORD);
|
||||
static BOOL (WINAPI *pSetupDiEnumDeviceInfo)(HDEVINFO, DWORD, PSP_DEVINFO_DATA);
|
||||
static BOOL (WINAPI *pSetupDiGetDeviceInstanceIdA)(HDEVINFO, PSP_DEVINFO_DATA, PTSTR, DWORD, PDWORD);
|
||||
static BOOL (WINAPI *pSetupDiGetDeviceRegistryPropertyA)(HDEVINFO, PSP_DEVINFO_DATA, DWORD, PDWORD, PBYTE, DWORD, PDWORD);
|
||||
static BOOL (WINAPI *pSetupDiDestroyDeviceInfoList)(HDEVINFO);
|
||||
|
||||
static int symlookup(HMODULE dll, void **addr, const char *sym)
|
||||
{
|
||||
*addr = GetProcAddress(dll, sym);
|
||||
if (*addr == NULL)
|
||||
{
|
||||
FreeLibrary(dll);
|
||||
return 0;
|
||||
} /* if */
|
||||
|
||||
return 1;
|
||||
} /* symlookup */
|
||||
|
||||
static int find_api_symbols(void)
|
||||
{
|
||||
HMODULE dll;
|
||||
|
||||
if (did_api_lookup)
|
||||
return 1;
|
||||
|
||||
#define LOOKUP(x) { if (!symlookup(dll, (void **) &p##x, #x)) return 0; }
|
||||
dll = LoadLibrary(TEXT("user32.dll"));
|
||||
if (dll == NULL)
|
||||
return 0;
|
||||
|
||||
LOOKUP(GetRawInputDeviceInfoA);
|
||||
LOOKUP(RegisterRawInputDevices);
|
||||
LOOKUP(GetRawInputDeviceList);
|
||||
LOOKUP(DefRawInputProc);
|
||||
LOOKUP(GetRawInputBuffer);
|
||||
LOOKUP(GetRawInputData);
|
||||
LOOKUP(CreateWindowExA);
|
||||
LOOKUP(RegisterClassExA);
|
||||
LOOKUP(UnregisterClassA);
|
||||
LOOKUP(DefWindowProcA);
|
||||
LOOKUP(PeekMessageA);
|
||||
LOOKUP(TranslateMessage);
|
||||
LOOKUP(DispatchMessageA);
|
||||
LOOKUP(DestroyWindow);
|
||||
|
||||
dll = LoadLibrary(TEXT("kernel32.dll"));
|
||||
if (dll == NULL)
|
||||
return 0;
|
||||
|
||||
LOOKUP(GetModuleHandleA);
|
||||
LOOKUP(GetLastError);
|
||||
LOOKUP(InitializeCriticalSection);
|
||||
LOOKUP(EnterCriticalSection);
|
||||
LOOKUP(LeaveCriticalSection);
|
||||
LOOKUP(DeleteCriticalSection);
|
||||
|
||||
dll = LoadLibrary(TEXT("setupapi.dll"));
|
||||
if (dll == NULL)
|
||||
return 0;
|
||||
|
||||
LOOKUP(SetupDiGetClassDevsA);
|
||||
LOOKUP(SetupDiEnumDeviceInfo);
|
||||
LOOKUP(SetupDiGetDeviceInstanceIdA);
|
||||
LOOKUP(SetupDiGetDeviceRegistryPropertyA);
|
||||
LOOKUP(SetupDiDestroyDeviceInfoList);
|
||||
|
||||
#undef LOOKUP
|
||||
|
||||
did_api_lookup = 1;
|
||||
return 1;
|
||||
} /* find_api_symbols */
|
||||
|
||||
|
||||
/* Some simple functions to avoid C runtime dependency... */
|
||||
|
||||
static char make_upper(const char a)
|
||||
{
|
||||
return ((a >= 'a') && (a <= 'z')) ? (a - ('a' - 'A')) : a;
|
||||
} /* make_upper */
|
||||
|
||||
static void make_string_upper(char *str)
|
||||
{
|
||||
char *ptr;
|
||||
for (ptr = str; *ptr; ptr++)
|
||||
*ptr = make_upper(*ptr);
|
||||
} /* make_string_upper */
|
||||
|
||||
static int string_compare(const char *a, const char *b)
|
||||
{
|
||||
while (1)
|
||||
{
|
||||
const char cha = *(a++);
|
||||
const char chb = *(b++);
|
||||
if (cha < chb)
|
||||
return -1;
|
||||
else if (cha > chb)
|
||||
return 1;
|
||||
else if (cha == '\0')
|
||||
return 0;
|
||||
} /* while */
|
||||
|
||||
return 0;
|
||||
} /* string_compare */
|
||||
|
||||
static size_t string_length(const char *a)
|
||||
{
|
||||
size_t retval;
|
||||
for (retval = 0; *(a++); retval++) { /* spin. */ }
|
||||
return retval;
|
||||
} /* string_length */
|
||||
|
||||
|
||||
static void queue_event(const ManyMouseEvent *event)
|
||||
{
|
||||
/* copy the event info. We'll process it in ManyMouse_PollEvent(). */
|
||||
CopyMemory(&input_events[input_events_write], event, sizeof (ManyMouseEvent));
|
||||
|
||||
input_events_write = ((input_events_write + 1) % MAX_EVENTS);
|
||||
|
||||
/* Ring buffer full? Lose oldest event. */
|
||||
if (input_events_write == input_events_read)
|
||||
{
|
||||
/* !!! FIXME: we need to not lose mouse buttons here. */
|
||||
input_events_read = ((input_events_read + 1) % MAX_EVENTS);
|
||||
} /* if */
|
||||
} /* queue_event */
|
||||
|
||||
|
||||
static void queue_from_rawinput(const RAWINPUT *raw)
|
||||
{
|
||||
int i;
|
||||
const RAWINPUTHEADER *header = &raw->header;
|
||||
const RAWMOUSE *mouse = &raw->data.mouse;
|
||||
const RAWKEYBOARD *keyboard = &raw->data.keyboard;
|
||||
ManyMouseEvent event;
|
||||
|
||||
if (raw->header.dwType != RIM_TYPEMOUSE && raw->header.dwType != RIM_TYPEKEYBOARD)
|
||||
return;
|
||||
|
||||
for (i = 0; i < available_devices; i++) /* find the device for event. */
|
||||
{
|
||||
if (mice[i].handle == header->hDevice)
|
||||
break;
|
||||
} /* for */
|
||||
|
||||
if (i == available_devices)
|
||||
return; /* not found?! */
|
||||
|
||||
/*
|
||||
* RAWINPUT packs a bunch of events into one, so we split it up into
|
||||
* a bunch of ManyMouseEvents here and store them in an internal queue.
|
||||
* Then ManyMouse_PollEvent() just shuffles items off that queue
|
||||
* without any complicated processing.
|
||||
*/
|
||||
|
||||
event.device = i;
|
||||
|
||||
pEnterCriticalSection(&mutex);
|
||||
|
||||
event.iskeyboard = mice[i].iskeyboard;
|
||||
if(raw->header.dwType == RIM_TYPEKEYBOARD)
|
||||
{
|
||||
event.type = MANYMOUSE_EVENT_KEYBOARD;
|
||||
event.item = keyboard->VKey;
|
||||
if(keyboard->Message == WM_KEYDOWN || keyboard->Message == WM_SYSKEYDOWN) // pressed down
|
||||
event.value = 1;
|
||||
else if(keyboard->Message == WM_KEYUP || keyboard->Message == WM_SYSKEYUP) // pressed up
|
||||
event.value = 0;
|
||||
else // unhandled exception
|
||||
{
|
||||
pLeaveCriticalSection(&mutex);
|
||||
return;
|
||||
}
|
||||
queue_event(&event);
|
||||
pLeaveCriticalSection(&mutex);
|
||||
return;
|
||||
}
|
||||
|
||||
if (mouse->usFlags & MOUSE_MOVE_ABSOLUTE)
|
||||
{
|
||||
/* !!! FIXME: How do we get the min and max values for absmotion? */
|
||||
event.type = MANYMOUSE_EVENT_ABSMOTION;
|
||||
event.item = 0;
|
||||
event.value = mouse->lLastX;
|
||||
queue_event(&event);
|
||||
event.item = 1;
|
||||
event.value = mouse->lLastY;
|
||||
queue_event(&event);
|
||||
} /* if */
|
||||
|
||||
else /*if (mouse->usFlags & MOUSE_MOVE_RELATIVE)*/
|
||||
{
|
||||
event.type = MANYMOUSE_EVENT_RELMOTION;
|
||||
if (mouse->lLastX != 0)
|
||||
{
|
||||
event.item = 0;
|
||||
event.value = mouse->lLastX;
|
||||
queue_event(&event);
|
||||
} /* if */
|
||||
|
||||
if (mouse->lLastY != 0)
|
||||
{
|
||||
event.item = 1;
|
||||
event.value = mouse->lLastY;
|
||||
queue_event(&event);
|
||||
} /* if */
|
||||
} /* else if */
|
||||
|
||||
event.type = MANYMOUSE_EVENT_BUTTON;
|
||||
|
||||
#define QUEUE_BUTTON(x) { \
|
||||
if (mouse->usButtonFlags & RI_MOUSE_BUTTON_##x##_DOWN) { \
|
||||
event.item = x-1; \
|
||||
event.value = 1; \
|
||||
queue_event(&event); \
|
||||
} \
|
||||
if (mouse->usButtonFlags & RI_MOUSE_BUTTON_##x##_UP) { \
|
||||
event.item = x-1; \
|
||||
event.value = 0; \
|
||||
queue_event(&event); \
|
||||
} \
|
||||
}
|
||||
|
||||
QUEUE_BUTTON(1);
|
||||
QUEUE_BUTTON(2);
|
||||
QUEUE_BUTTON(3);
|
||||
QUEUE_BUTTON(4);
|
||||
QUEUE_BUTTON(5);
|
||||
|
||||
#undef QUEUE_BUTTON
|
||||
|
||||
if (mouse->usButtonFlags & RI_MOUSE_WHEEL)
|
||||
{
|
||||
if (mouse->usButtonData != 0) /* !!! FIXME: can this ever be zero? */
|
||||
{
|
||||
event.type = MANYMOUSE_EVENT_SCROLL;
|
||||
event.item = 0; /* !!! FIXME: horizontal wheel? */
|
||||
event.value = ( ((SHORT) mouse->usButtonData) > 0) ? 1 : -1;
|
||||
queue_event(&event);
|
||||
} /* if */
|
||||
} /* if */
|
||||
|
||||
pLeaveCriticalSection(&mutex);
|
||||
} /* queue_from_rawinput */
|
||||
|
||||
|
||||
static void wminput_handler(WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
UINT dwSize = 0;
|
||||
LPBYTE lpb;
|
||||
|
||||
pGetRawInputData((HRAWINPUT) lParam, RID_INPUT, NULL, &dwSize,
|
||||
sizeof (RAWINPUTHEADER));
|
||||
|
||||
if (dwSize < sizeof (RAWKEYBOARD))
|
||||
return; /* unexpected packet? */
|
||||
|
||||
lpb = (LPBYTE) alloca(dwSize);
|
||||
if (lpb == NULL)
|
||||
return;
|
||||
if (pGetRawInputData((HRAWINPUT) lParam, RID_INPUT, lpb, &dwSize,
|
||||
sizeof (RAWINPUTHEADER)) != dwSize)
|
||||
return;
|
||||
|
||||
queue_from_rawinput((RAWINPUT *) lpb);
|
||||
} /* wminput_handler */
|
||||
|
||||
|
||||
static LRESULT CALLBACK RawWndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
if (Msg == WM_INPUT)
|
||||
wminput_handler(wParam, lParam);
|
||||
|
||||
else if (Msg == WM_DESTROY)
|
||||
return 0;
|
||||
|
||||
return pDefWindowProcA(hWnd, Msg, wParam, lParam);
|
||||
} /* RawWndProc */
|
||||
|
||||
|
||||
static int init_event_queue(void)
|
||||
{
|
||||
HINSTANCE hInstance = pGetModuleHandleA(NULL);
|
||||
WNDCLASSEX wce;
|
||||
RAWINPUTDEVICE rid[2];
|
||||
|
||||
ZeroMemory(input_events, sizeof (input_events));
|
||||
input_events_read = input_events_write = 0;
|
||||
|
||||
ZeroMemory(&wce, sizeof (wce));
|
||||
wce.cbSize = sizeof(WNDCLASSEX);
|
||||
wce.lpfnWndProc = RawWndProc;
|
||||
wce.lpszClassName = class_name;
|
||||
wce.hInstance = hInstance;
|
||||
class_atom = pRegisterClassExA(&wce);
|
||||
if (class_atom == 0)
|
||||
return 0;
|
||||
|
||||
raw_hwnd = pCreateWindowExA(0, class_name, win_name, WS_OVERLAPPEDWINDOW,
|
||||
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
|
||||
CW_USEDEFAULT, HWND_MESSAGE, NULL, hInstance, NULL);
|
||||
|
||||
if (raw_hwnd == NULL)
|
||||
return 0;
|
||||
|
||||
pInitializeCriticalSection(&mutex);
|
||||
|
||||
ZeroMemory(rid, sizeof (rid));
|
||||
rid[0].usUsagePage = 1; /* GenericDesktop page */
|
||||
rid[0].usUsage = 2; /* GeneralDestop Mouse usage. */
|
||||
rid[0].dwFlags = RIDEV_INPUTSINK;
|
||||
rid[0].hwndTarget = raw_hwnd;
|
||||
rid[1].usUsagePage = 1; /* GenericDesktop page */
|
||||
rid[1].usUsage = 6; /* GeneralDestop Keyboard usage. */
|
||||
rid[1].dwFlags = RIDEV_INPUTSINK;
|
||||
rid[1].hwndTarget = raw_hwnd;
|
||||
if (!pRegisterRawInputDevices(rid, 2, sizeof (RAWINPUTDEVICE)))
|
||||
{
|
||||
pDeleteCriticalSection(&mutex);
|
||||
return 0;
|
||||
} /* if */
|
||||
|
||||
return 1;
|
||||
} /* init_event_queue */
|
||||
|
||||
|
||||
static void cleanup_window(void)
|
||||
{
|
||||
if (raw_hwnd)
|
||||
{
|
||||
MSG Msg;
|
||||
pDestroyWindow(raw_hwnd);
|
||||
while (pPeekMessageA(&Msg, raw_hwnd, 0, 0, PM_REMOVE))
|
||||
{
|
||||
pTranslateMessage(&Msg);
|
||||
pDispatchMessageA(&Msg);
|
||||
} /* while */
|
||||
raw_hwnd = 0;
|
||||
} /* if */
|
||||
|
||||
if (class_atom)
|
||||
{
|
||||
pUnregisterClassA(class_name, pGetModuleHandleA(NULL));
|
||||
class_atom = 0;
|
||||
} /* if */
|
||||
} /* cleanup_window */
|
||||
|
||||
|
||||
static int get_devinfo_data(HDEVINFO devinfo, const char *devinstance,
|
||||
SP_DEVINFO_DATA *data)
|
||||
{
|
||||
DWORD i = 0;
|
||||
const DWORD bufsize = string_length(devinstance) + 1;
|
||||
char *buf = (char *) alloca(bufsize);
|
||||
if (buf == NULL)
|
||||
return 0;
|
||||
|
||||
while (1)
|
||||
{
|
||||
ZeroMemory(data, sizeof (SP_DEVINFO_DATA));
|
||||
data->cbSize = sizeof (SP_DEVINFO_DATA);
|
||||
if (!pSetupDiEnumDeviceInfo(devinfo, i++, data))
|
||||
{
|
||||
if (pGetLastError() == ERROR_NO_MORE_ITEMS)
|
||||
break;
|
||||
else
|
||||
continue;
|
||||
} /* if */
|
||||
|
||||
if (!pSetupDiGetDeviceInstanceIdA(devinfo, data, buf, bufsize, NULL))
|
||||
continue;
|
||||
|
||||
make_string_upper(buf);
|
||||
if (string_compare(devinstance, buf) == 0)
|
||||
return 1; /* found it! */
|
||||
} /* while */
|
||||
|
||||
return 0; /* not found. */
|
||||
} /* get_devinfo_data */
|
||||
|
||||
|
||||
static void get_dev_name_by_instance(const char *devinstance, char *name,
|
||||
size_t namesize)
|
||||
{
|
||||
SP_DEVINFO_DATA devdata;
|
||||
const DWORD flags = DIGCF_ALLCLASSES | DIGCF_PRESENT;
|
||||
HDEVINFO devinfo = pSetupDiGetClassDevsA(NULL, NULL, NULL, flags);
|
||||
if (devinfo == INVALID_HANDLE_VALUE)
|
||||
return;
|
||||
|
||||
if (get_devinfo_data(devinfo, devinstance, &devdata))
|
||||
{
|
||||
pSetupDiGetDeviceRegistryPropertyA(devinfo, &devdata, SPDRP_DEVICEDESC,
|
||||
NULL, (PBYTE) name, namesize, NULL);
|
||||
} /* if */
|
||||
|
||||
pSetupDiDestroyDeviceInfoList(devinfo);
|
||||
} /* get_dev_name_by_instance */
|
||||
|
||||
|
||||
static void get_device_product_name(char *name, size_t namesize, char *devname)
|
||||
{
|
||||
const char default_device_name[] = "Unidentified input device";
|
||||
|
||||
*name = '\0'; /* really insane default. */
|
||||
if (sizeof (default_device_name) >= namesize)
|
||||
return;
|
||||
|
||||
/* in case we can't stumble upon something better... */
|
||||
CopyMemory(name, default_device_name, sizeof (default_device_name));
|
||||
|
||||
/* okay, we're got the device instance. Now find the data for it. */
|
||||
get_dev_name_by_instance(devname, name, namesize);
|
||||
} /* get_device_product_name */
|
||||
|
||||
|
||||
static void init_mouse(const RAWINPUTDEVICELIST *dev)
|
||||
{
|
||||
const char rdp_ident_kb[] = "ROOT\\RDP_KBD\\";
|
||||
const char rdp_ident_mi[] = "ROOT\\RDP_MOU\\";
|
||||
MouseStruct *mouse = &mice[available_devices];
|
||||
char *buf = NULL;
|
||||
char *ptr = NULL;
|
||||
UINT ct = 0;
|
||||
|
||||
if (dev->dwType != RIM_TYPEMOUSE && dev->dwType != RIM_TYPEKEYBOARD)
|
||||
return; /* if not keyboard or mice (some other fruity thing). */
|
||||
|
||||
if (pGetRawInputDeviceInfoA(dev->hDevice, RIDI_DEVICENAME, NULL, &ct) < 0)
|
||||
return;
|
||||
|
||||
/* ct == is chars, not bytes, but we used the ASCII version. */
|
||||
buf = (char *) alloca(ct+1);
|
||||
if (buf == NULL)
|
||||
return;
|
||||
|
||||
if (pGetRawInputDeviceInfoA(dev->hDevice, RIDI_DEVICENAME, buf, &ct) < 0)
|
||||
return;
|
||||
|
||||
buf[ct] = '\0'; /* make sure it's null-terminated. */
|
||||
|
||||
/* XP starts these strings with "\\??\\" ... Vista does "\\\\?\\". :/ */
|
||||
while ((*buf == '?') || (*buf == '\\'))
|
||||
{
|
||||
buf++;
|
||||
ct--;
|
||||
} /* while */
|
||||
|
||||
/* This string tap dancing gets us the device instance id. */
|
||||
for (ptr = buf; *ptr; ptr++) /* convert '#' to '\\' ... */
|
||||
{
|
||||
char ch = *ptr;
|
||||
if (ch == '#')
|
||||
*ptr = '\\';
|
||||
else if (ch == '{') /* hit the GUID part of the string. */
|
||||
{
|
||||
if (*(ptr-1) == '\\')
|
||||
ptr--;
|
||||
break;
|
||||
} /* else if */
|
||||
} /* for */
|
||||
|
||||
*ptr = '\0';
|
||||
|
||||
make_string_upper(buf);
|
||||
|
||||
/*
|
||||
* Apparently there's a fake "RDP" device...I guess this is
|
||||
* "Remote Desktop Protocol" for controlling the system pointer
|
||||
* remotely via Windows Remote Desktop, but that's just a guess.
|
||||
* At any rate, we don't want that device, so skip it if detected.
|
||||
*
|
||||
* Idea for this found here:
|
||||
* http://link.mywwwserver.com/~jstookey/arcade/rawmouse/raw_mouse.c
|
||||
*/
|
||||
|
||||
/* avoiding memcmp here so we don't get a C runtime dependency... */
|
||||
if (ct >= sizeof (rdp_ident_kb) - 1)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < sizeof (rdp_ident_kb) - 1; i++)
|
||||
{
|
||||
if (buf[i] != rdp_ident_kb[i])
|
||||
break;
|
||||
} /* for */
|
||||
|
||||
if (i == sizeof (rdp_ident_kb) - 1)
|
||||
return; /* this is an RDP thing. Skip this device. */
|
||||
} /* if */
|
||||
if (ct >= sizeof (rdp_ident_mi) - 1)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < sizeof (rdp_ident_mi) - 1; i++)
|
||||
{
|
||||
if (buf[i] != rdp_ident_mi[i])
|
||||
break;
|
||||
} /* for */
|
||||
|
||||
if (i == sizeof (rdp_ident_mi) - 1)
|
||||
return; /* this is an RDP thing. Skip this device. */
|
||||
} /* if */
|
||||
|
||||
/* accept this mouse! */
|
||||
ZeroMemory(mouse, sizeof (MouseStruct));
|
||||
get_device_product_name(mouse->name, sizeof (mouse->name), buf);
|
||||
mouse->handle = dev->hDevice;
|
||||
mouse->iskeyboard = dev->dwType == RIM_TYPEKEYBOARD ? 1 : 0;
|
||||
available_devices++;
|
||||
} /* init_mouse */
|
||||
|
||||
|
||||
static int windows_wminput_init(void)
|
||||
{
|
||||
RAWINPUTDEVICELIST *devlist = NULL;
|
||||
UINT ct = 0;
|
||||
UINT i;
|
||||
|
||||
available_devices = 0;
|
||||
|
||||
if (!find_api_symbols()) /* only supported on WinXP and later. */
|
||||
return -1;
|
||||
|
||||
pGetRawInputDeviceList(NULL, &ct, sizeof (RAWINPUTDEVICELIST));
|
||||
if (ct == 0) /* no devices. */
|
||||
return 0;
|
||||
|
||||
devlist = (PRAWINPUTDEVICELIST) alloca(sizeof (RAWINPUTDEVICELIST) * ct);
|
||||
pGetRawInputDeviceList(devlist, &ct, sizeof (RAWINPUTDEVICELIST));
|
||||
for (i = 0; i < ct; i++)
|
||||
init_mouse(&devlist[i]);
|
||||
|
||||
if (!init_event_queue())
|
||||
{
|
||||
cleanup_window();
|
||||
available_devices = 0;
|
||||
} /* if */
|
||||
|
||||
return available_devices;
|
||||
} /* windows_wminput_init */
|
||||
|
||||
|
||||
static void windows_wminput_quit(void)
|
||||
{
|
||||
/* unregister WM_INPUT devices... */
|
||||
RAWINPUTDEVICE rid[2];
|
||||
ZeroMemory(rid, sizeof (rid));
|
||||
rid[0].usUsagePage = 1; /* GenericDesktop page */
|
||||
rid[0].usUsage = 2; /* GeneralDestop Mouse usage. */
|
||||
rid[0].dwFlags |= RIDEV_REMOVE;
|
||||
rid[0].hwndTarget = raw_hwnd;
|
||||
rid[1].usUsagePage = 1; /* GenericDesktop page */
|
||||
rid[1].usUsage = 6; /* GeneralDestop Keyboard usage. */
|
||||
rid[1].dwFlags |= RIDEV_REMOVE;
|
||||
rid[1].hwndTarget = raw_hwnd;
|
||||
pRegisterRawInputDevices(rid, 2, sizeof (RAWINPUTDEVICE));
|
||||
cleanup_window();
|
||||
available_devices = 0;
|
||||
pDeleteCriticalSection(&mutex);
|
||||
} /* windows_wminput_quit */
|
||||
|
||||
|
||||
static const char *windows_wminput_name(unsigned int index, unsigned int iskeyboard)
|
||||
{
|
||||
return (index < available_devices && mice[index].iskeyboard == iskeyboard) ? mice[index].name : NULL;
|
||||
} /* windows_wminput_name */
|
||||
|
||||
|
||||
/*
|
||||
* Windows doesn't send a WM_INPUT event when you unplug a mouse,
|
||||
* so we try to do a basic query by device handle here; if the
|
||||
* query fails, we assume the device has vanished and generate a
|
||||
* disconnect.
|
||||
*/
|
||||
static int check_for_disconnects(ManyMouseEvent *ev)
|
||||
{
|
||||
/*
|
||||
* (i) is static so we iterate through all mice round-robin and check
|
||||
* one mouse per call to ManyMouse_PollEvent(). This makes this test O(1).
|
||||
*/
|
||||
static unsigned int i = 0;
|
||||
MouseStruct *mouse = NULL;
|
||||
|
||||
if (++i >= available_devices) /* check first in case of redetect */
|
||||
i = 0;
|
||||
|
||||
mouse = &mice[i];
|
||||
if (mouse->handle != NULL) /* not NULL == still plugged in. */
|
||||
{
|
||||
UINT size = 0;
|
||||
UINT rc = pGetRawInputDeviceInfoA(mouse->handle, RIDI_DEVICEINFO,
|
||||
NULL, &size);
|
||||
if (rc == (UINT) -1) /* failed...probably unplugged... */
|
||||
{
|
||||
mouse->handle = NULL;
|
||||
ev->type = MANYMOUSE_EVENT_DISCONNECT;
|
||||
ev->device = i;
|
||||
ev->iskeyboard = mouse->iskeyboard;
|
||||
return 1;
|
||||
} /* if */
|
||||
} /* if */
|
||||
|
||||
return 0; /* no disconnect event this time. */
|
||||
} /* check_for_disconnects */
|
||||
|
||||
|
||||
static int windows_wminput_poll(ManyMouseEvent *ev)
|
||||
{
|
||||
MSG Msg; /* run the queue for WM_INPUT messages, etc ... */
|
||||
int found = 0;
|
||||
|
||||
/* ...favor existing events in the queue... */
|
||||
pEnterCriticalSection(&mutex);
|
||||
if (input_events_read != input_events_write) /* no events if equal. */
|
||||
{
|
||||
CopyMemory(ev, &input_events[input_events_read], sizeof (*ev));
|
||||
input_events_read = ((input_events_read + 1) % MAX_EVENTS);
|
||||
found = 1;
|
||||
} /* if */
|
||||
pLeaveCriticalSection(&mutex);
|
||||
|
||||
if (!found)
|
||||
{
|
||||
/* pump Windows for new hardware events... */
|
||||
while (pPeekMessageA(&Msg, raw_hwnd, 0, 0, PM_REMOVE))
|
||||
{
|
||||
pTranslateMessage(&Msg);
|
||||
pDispatchMessageA(&Msg);
|
||||
} /* while */
|
||||
|
||||
/* In case something new came in, give it to the app... */
|
||||
pEnterCriticalSection(&mutex);
|
||||
if (input_events_read != input_events_write) /* no events if equal. */
|
||||
{
|
||||
CopyMemory(ev, &input_events[input_events_read], sizeof (*ev));
|
||||
input_events_read = ((input_events_read + 1) % MAX_EVENTS);
|
||||
found = 1;
|
||||
} /* if */
|
||||
pLeaveCriticalSection(&mutex);
|
||||
} /* if */
|
||||
|
||||
/*
|
||||
* Check for disconnects if queue is totally empty and Windows didn't
|
||||
* report anything new at this time. This ensures that we don't send a
|
||||
* disconnect event through ManyMouse and then later give a valid
|
||||
* event to the app for a device that is now missing.
|
||||
*/
|
||||
if (!found)
|
||||
found = check_for_disconnects(ev);
|
||||
|
||||
return found;
|
||||
} /* windows_wminput_poll */
|
||||
|
||||
static const ManyMouseDriver ManyMouseDriver_interface =
|
||||
{
|
||||
"Windows XP and later WM_INPUT interface",
|
||||
windows_wminput_init,
|
||||
windows_wminput_quit,
|
||||
windows_wminput_name,
|
||||
windows_wminput_poll
|
||||
};
|
||||
|
||||
const ManyMouseDriver *ManyMouseDriver_windows = &ManyMouseDriver_interface;
|
||||
|
||||
#else
|
||||
const ManyMouseDriver *ManyMouseDriver_windows = 0;
|
||||
#endif /* ifdef Windows blocker */
|
||||
|
||||
/* end of windows_wminput.c ... */
|
||||
|
||||
@@ -1,127 +0,0 @@
|
||||
//==========================================================================
|
||||
// Mouse Injector Plugin
|
||||
//==========================================================================
|
||||
// Copyright (C) 2016-2021 Carnivorous
|
||||
// All rights reserved.
|
||||
//
|
||||
// Mouse Injector 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, visit http://www.gnu.org/licenses/gpl-2.0.html
|
||||
//==========================================================================
|
||||
#ifndef IDC_STATIC
|
||||
#define IDC_STATIC (-1)
|
||||
#endif
|
||||
|
||||
#define IDC_CONFIGWINDOW 1
|
||||
#define IDC_CONFIGBOXINFO 100
|
||||
#define IDC_STATICPRIM 101
|
||||
#define IDC_STATICSEC 102
|
||||
#define IDC_CONFIGBOX 103
|
||||
#define IDC_LABEL00 104
|
||||
#define IDC_LABEL01 105
|
||||
#define IDC_LABEL02 106
|
||||
#define IDC_LABEL03 107
|
||||
#define IDC_LABEL04 108
|
||||
#define IDC_LABEL05 109
|
||||
#define IDC_LABEL06 110
|
||||
#define IDC_LABEL07 111
|
||||
#define IDC_LABEL08 112
|
||||
#define IDC_LABEL09 113
|
||||
#define IDC_LABEL10 114
|
||||
#define IDC_LABEL11 115
|
||||
#define IDC_LABEL12 116
|
||||
#define IDC_LABEL13 117
|
||||
#define IDC_LABEL14 118
|
||||
#define IDC_LABEL15 119
|
||||
#define IDC_LABEL16 120
|
||||
#define IDC_LABEL17 121
|
||||
#define IDC_PRIMARY00 122
|
||||
#define IDC_PRIMARY01 123
|
||||
#define IDC_PRIMARY02 124
|
||||
#define IDC_PRIMARY03 125
|
||||
#define IDC_PRIMARY04 126
|
||||
#define IDC_PRIMARY05 127
|
||||
#define IDC_PRIMARY06 128
|
||||
#define IDC_PRIMARY07 129
|
||||
#define IDC_PRIMARY08 130
|
||||
#define IDC_PRIMARY09 131
|
||||
#define IDC_PRIMARY10 132
|
||||
#define IDC_PRIMARY11 133
|
||||
#define IDC_PRIMARY12 134
|
||||
#define IDC_PRIMARY13 135
|
||||
#define IDC_PRIMARY14 136
|
||||
#define IDC_PRIMARY15 137
|
||||
#define IDC_PRIMARY16 138
|
||||
#define IDC_PRIMARY17 139
|
||||
#define IDC_SECONDARY00 140
|
||||
#define IDC_SECONDARY01 141
|
||||
#define IDC_SECONDARY02 142
|
||||
#define IDC_SECONDARY03 143
|
||||
#define IDC_SECONDARY04 144
|
||||
#define IDC_SECONDARY05 145
|
||||
#define IDC_SECONDARY06 146
|
||||
#define IDC_SECONDARY07 147
|
||||
#define IDC_SECONDARY08 148
|
||||
#define IDC_SECONDARY09 149
|
||||
#define IDC_SECONDARY10 150
|
||||
#define IDC_SECONDARY11 151
|
||||
#define IDC_SECONDARY12 152
|
||||
#define IDC_SECONDARY13 153
|
||||
#define IDC_SECONDARY14 154
|
||||
#define IDC_SECONDARY15 155
|
||||
#define IDC_SECONDARY16 156
|
||||
#define IDC_SECONDARY17 157
|
||||
#define IDC_LOCK_LABEL 158
|
||||
#define IDC_LOCK 159
|
||||
#define IDC_MOUSESELECT 160
|
||||
#define IDC_KEYBOARDSELECT 161
|
||||
#define IDC_MOUSESELECTINFO 162
|
||||
#define IDC_KEYBOARDSELECTINFO 163
|
||||
#define IDC_SLIDER_STATIC00 164
|
||||
#define IDC_SLIDER_DISPLAY00 165
|
||||
#define IDC_SLIDER_STATIC01 166
|
||||
#define IDC_SLIDER_DISPLAY01 167
|
||||
#define IDC_SLIDER_STATIC02 168
|
||||
#define IDC_SLIDER_DISPLAY02 169
|
||||
#define IDC_SLIDER00 170
|
||||
#define IDC_SLIDER01 171
|
||||
#define IDC_SLIDER02 172
|
||||
#define IDC_INVERTPITCH 173
|
||||
#define IDC_CROUCHTOGGLE 174
|
||||
#define IDC_GECURSORAIMING 175
|
||||
#define IDC_PDCURSORAIMING 176
|
||||
#define IDC_ALLPLAYERS 177
|
||||
#define IDC_RATIOSTATIC 178
|
||||
#define IDC_RATIOWIDTH 179
|
||||
#define IDC_RATIOSTATICX 180
|
||||
#define IDC_RATIOHEIGHT 181
|
||||
#define IDC_RESETFOV 182
|
||||
#define IDC_FOV_DEGREES 183
|
||||
#define IDC_FOV 184
|
||||
#define IDC_FOV_NOTE 185
|
||||
#define IDC_GESHOWCROSSHAIR 186
|
||||
#define IDC_BYPASSVIEWMODELFOVWEAK 187
|
||||
#define IDC_INFOBOX 188
|
||||
#define IDC_INFO 189
|
||||
#define IDC_REVERT 190
|
||||
#define IDC_OK 191
|
||||
#define IDC_CANCEL 192
|
||||
#define IDC_CLEAR 193
|
||||
#define IDC_HELPPOPUP 194
|
||||
#define IDC_PLAYER1 195
|
||||
#define IDC_PLAYER2 196
|
||||
#define IDC_PLAYER3 197
|
||||
#define IDC_PLAYER4 198
|
||||
#define IDC_DETECTDEVICE 199
|
||||
#define IDC_LOCKONFOCUS 200
|
||||
#define IDC_UNLOCKONWINLOSS 201
|
||||
#define IDC_PARTITION IDC_STATIC
|
||||
@@ -1,165 +0,0 @@
|
||||
//==========================================================================
|
||||
// Mouse Injector Plugin
|
||||
//==========================================================================
|
||||
// Copyright (C) 2016-2021 Carnivorous
|
||||
// All rights reserved.
|
||||
//
|
||||
// Mouse Injector 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, visit http://www.gnu.org/licenses/gpl-2.0.html
|
||||
//==========================================================================
|
||||
#include <windows.h>
|
||||
#include <commctrl.h>
|
||||
#include <richedit.h>
|
||||
#include "resource.h"
|
||||
|
||||
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
|
||||
IDC_CONFIGWINDOW DIALOGEX 0, 0, 470, 368
|
||||
STYLE DS_3DLOOK | DS_CENTER | DS_MODALFRAME | DS_SHELLFONT | WS_CAPTION | WS_CLIPSIBLINGS | WS_POPUP
|
||||
EXSTYLE WS_EX_CONTROLPARENT
|
||||
CAPTION "Mouse Injector - Input Settings"
|
||||
FONT 8, "MS Shell Dlg", 0, 0, 0
|
||||
{
|
||||
AUTORADIOBUTTON "Player 1", IDC_PLAYER1, 11, 8, 41, 8, WS_GROUP | WS_TABSTOP, WS_EX_LEFT
|
||||
AUTORADIOBUTTON "Player 2", IDC_PLAYER2, 56, 8, 41, 8, WS_TABSTOP, WS_EX_LEFT
|
||||
AUTORADIOBUTTON "Player 3", IDC_PLAYER3, 101, 8, 41, 8, WS_TABSTOP, WS_EX_LEFT
|
||||
AUTORADIOBUTTON "Player 4", IDC_PLAYER4, 146, 8, 41, 8, WS_TABSTOP, WS_EX_LEFT
|
||||
PUSHBUTTON "Detect Input Devices", IDC_DETECTDEVICE, 375, 7, 76, 12, NOT WS_VISIBLE, WS_EX_LEFT
|
||||
CTEXT "", IDC_PARTITION, 7, 22, 456, 2, NOT WS_TABSTOP | SS_CENTER | SS_SUNKEN, WS_EX_LEFT
|
||||
RTEXT "Profile", IDC_CONFIGBOXINFO, 17, 32, 70, 12, SS_RIGHT | SS_CENTERIMAGE, WS_EX_RIGHT
|
||||
COMBOBOX IDC_CONFIGBOX, 97, 32, 150, 120, WS_TABSTOP | WS_VSCROLL | CBS_DROPDOWNLIST, WS_EX_LEFT
|
||||
CTEXT "Primary", IDC_STATICPRIM, 97, 47, 70, 15, SS_CENTER | SS_CENTERIMAGE, WS_EX_LEFT
|
||||
CTEXT "Secondary", IDC_STATICSEC, 177, 47, 70, 15, SS_CENTER | SS_CENTERIMAGE, WS_EX_LEFT
|
||||
RTEXT "Forward", IDC_LABEL00, 17, 62, 70, 15, SS_RIGHT | SS_CENTERIMAGE, WS_EX_TRANSPARENT
|
||||
PUSHBUTTON "", IDC_PRIMARY00, 97, 63, 70, 13, BS_FLAT, WS_EX_LEFT
|
||||
PUSHBUTTON "", IDC_SECONDARY00, 177, 63, 70, 13, BS_FLAT, WS_EX_LEFT
|
||||
RTEXT "Backwards", IDC_LABEL01, 17, 77, 70, 15, SS_RIGHT | SS_CENTERIMAGE, WS_EX_TRANSPARENT
|
||||
PUSHBUTTON "", IDC_PRIMARY01, 97, 78, 70, 13, BS_FLAT, WS_EX_LEFT
|
||||
PUSHBUTTON "", IDC_SECONDARY01, 177, 78, 70, 13, BS_FLAT, WS_EX_LEFT
|
||||
RTEXT "Strafe Left", IDC_LABEL02, 17, 92, 70, 15, SS_RIGHT | SS_CENTERIMAGE, WS_EX_TRANSPARENT
|
||||
PUSHBUTTON "", IDC_PRIMARY02, 97, 93, 70, 13, BS_FLAT, WS_EX_LEFT
|
||||
PUSHBUTTON "", IDC_SECONDARY02, 177, 93, 70, 13, BS_FLAT, WS_EX_LEFT
|
||||
RTEXT "Strafe Right", IDC_LABEL03, 17, 107, 70, 15, SS_RIGHT | SS_CENTERIMAGE, WS_EX_TRANSPARENT
|
||||
PUSHBUTTON "", IDC_PRIMARY03, 97, 108, 70, 13, BS_FLAT, WS_EX_LEFT
|
||||
PUSHBUTTON "", IDC_SECONDARY03, 177, 108, 70, 13, BS_FLAT, WS_EX_LEFT
|
||||
RTEXT "Fire", IDC_LABEL04, 17, 122, 70, 15, SS_RIGHT | SS_CENTERIMAGE, WS_EX_TRANSPARENT
|
||||
PUSHBUTTON "", IDC_PRIMARY04, 97, 123, 70, 13, BS_FLAT, WS_EX_LEFT
|
||||
PUSHBUTTON "", IDC_SECONDARY04, 177, 123, 70, 13, BS_FLAT, WS_EX_LEFT
|
||||
RTEXT "Aim", IDC_LABEL05, 17, 137, 70, 15, SS_RIGHT | SS_CENTERIMAGE, WS_EX_TRANSPARENT
|
||||
PUSHBUTTON "", IDC_PRIMARY05, 97, 138, 70, 13, BS_FLAT, WS_EX_LEFT
|
||||
PUSHBUTTON "", IDC_SECONDARY05, 177, 138, 70, 13, BS_FLAT, WS_EX_LEFT
|
||||
RTEXT "Reload", IDC_LABEL06, 17, 152, 70, 15, SS_RIGHT | SS_CENTERIMAGE, WS_EX_TRANSPARENT
|
||||
PUSHBUTTON "", IDC_PRIMARY06, 97, 153, 70, 13, BS_FLAT, WS_EX_LEFT
|
||||
PUSHBUTTON "", IDC_SECONDARY06, 177, 153, 70, 13, BS_FLAT, WS_EX_LEFT
|
||||
RTEXT "Next Weapon/Accept", IDC_LABEL07, 17, 167, 70, 15, SS_RIGHT | SS_CENTERIMAGE, WS_EX_TRANSPARENT
|
||||
PUSHBUTTON "", IDC_PRIMARY07, 97, 168, 70, 13, BS_FLAT, WS_EX_LEFT
|
||||
PUSHBUTTON "", IDC_SECONDARY07, 177, 168, 70, 13, BS_FLAT, WS_EX_LEFT
|
||||
RTEXT "Activate/Cancel", IDC_LABEL08, 17, 182, 70, 15, SS_RIGHT | SS_CENTERIMAGE, WS_EX_TRANSPARENT
|
||||
PUSHBUTTON "", IDC_PRIMARY08, 97, 183, 70, 13, BS_FLAT, WS_EX_LEFT
|
||||
PUSHBUTTON "", IDC_SECONDARY08, 177, 183, 70, 13, BS_FLAT, WS_EX_LEFT
|
||||
RTEXT "Start", IDC_LABEL09, 17, 197, 70, 15, SS_RIGHT | SS_CENTERIMAGE, WS_EX_TRANSPARENT
|
||||
PUSHBUTTON "", IDC_PRIMARY09, 97, 198, 70, 13, BS_FLAT, WS_EX_LEFT
|
||||
PUSHBUTTON "", IDC_SECONDARY09, 177, 198, 70, 13, BS_FLAT, WS_EX_LEFT
|
||||
RTEXT "Crouch", IDC_LABEL10, 17, 212, 70, 15, SS_RIGHT | SS_CENTERIMAGE, WS_EX_TRANSPARENT
|
||||
PUSHBUTTON "", IDC_PRIMARY10, 97, 213, 70, 13, BS_FLAT, WS_EX_LEFT
|
||||
PUSHBUTTON "", IDC_SECONDARY10, 177, 213, 70, 13, BS_FLAT, WS_EX_LEFT
|
||||
RTEXT "(PD) Kneel", IDC_LABEL11, 17, 227, 70, 15, SS_RIGHT | SS_CENTERIMAGE, WS_EX_TRANSPARENT
|
||||
PUSHBUTTON "", IDC_PRIMARY11, 97, 228, 70, 13, BS_FLAT, WS_EX_LEFT
|
||||
PUSHBUTTON "", IDC_SECONDARY11, 177, 228, 70, 13, BS_FLAT, WS_EX_LEFT
|
||||
RTEXT "Previous Weapon", IDC_LABEL12, 17, 242, 70, 15, SS_RIGHT | SS_CENTERIMAGE, WS_EX_TRANSPARENT
|
||||
PUSHBUTTON "", IDC_PRIMARY12, 97, 243, 70, 13, BS_FLAT, WS_EX_LEFT
|
||||
PUSHBUTTON "", IDC_SECONDARY12, 177, 243, 70, 13, BS_FLAT, WS_EX_LEFT
|
||||
RTEXT "Next Weapon", IDC_LABEL13, 17, 257, 70, 15, SS_RIGHT | SS_CENTERIMAGE, WS_EX_TRANSPARENT
|
||||
PUSHBUTTON "", IDC_PRIMARY13, 97, 258, 70, 13, BS_FLAT, WS_EX_LEFT
|
||||
PUSHBUTTON "", IDC_SECONDARY13, 177, 258, 70, 13, BS_FLAT, WS_EX_LEFT
|
||||
RTEXT "Analog Up", IDC_LABEL14, 17, 272, 70, 15, SS_RIGHT | SS_CENTERIMAGE, WS_EX_TRANSPARENT
|
||||
PUSHBUTTON "", IDC_PRIMARY14, 97, 273, 70, 13, BS_FLAT, WS_EX_LEFT
|
||||
PUSHBUTTON "", IDC_SECONDARY14, 177, 273, 70, 13, BS_FLAT, WS_EX_LEFT
|
||||
RTEXT "Analog Down", IDC_LABEL15, 17, 287, 70, 15, SS_RIGHT | SS_CENTERIMAGE, WS_EX_TRANSPARENT
|
||||
PUSHBUTTON "", IDC_PRIMARY15, 97, 288, 70, 13, BS_FLAT, WS_EX_LEFT
|
||||
PUSHBUTTON "", IDC_SECONDARY15, 177, 288, 70, 13, BS_FLAT, WS_EX_LEFT
|
||||
RTEXT "Analog Left", IDC_LABEL16, 17, 301, 70, 15, SS_RIGHT | SS_CENTERIMAGE, WS_EX_TRANSPARENT
|
||||
PUSHBUTTON "", IDC_PRIMARY16, 97, 303, 70, 13, BS_FLAT, WS_EX_LEFT
|
||||
PUSHBUTTON "", IDC_SECONDARY16, 177, 303, 70, 13, BS_FLAT, WS_EX_LEFT
|
||||
RTEXT "Analog Right", IDC_LABEL17, 17, 316, 70, 15, SS_RIGHT | SS_CENTERIMAGE, WS_EX_TRANSPARENT
|
||||
PUSHBUTTON "", IDC_PRIMARY17, 97, 318, 70, 13, BS_FLAT, WS_EX_LEFT
|
||||
PUSHBUTTON "", IDC_SECONDARY17, 177, 318, 70, 13, BS_FLAT, WS_EX_LEFT
|
||||
RTEXT "Mouse", IDC_MOUSESELECTINFO, 265, 32, 31, 12, SS_RIGHT | SS_CENTERIMAGE, WS_EX_RIGHT
|
||||
COMBOBOX IDC_MOUSESELECT, 301, 32, 151, 120, WS_TABSTOP | WS_VSCROLL | CBS_DROPDOWNLIST, WS_EX_LEFT
|
||||
RTEXT "Keyboard", IDC_KEYBOARDSELECTINFO, 265, 49, 31, 12, SS_RIGHT | SS_CENTERIMAGE, WS_EX_RIGHT
|
||||
COMBOBOX IDC_KEYBOARDSELECT, 301, 49, 151, 120, WS_TABSTOP | WS_VSCROLL | CBS_DROPDOWNLIST, WS_EX_LEFT
|
||||
RTEXT "Mouse Sensitivity:", IDC_SLIDER_STATIC00, 329, 67, 100, 9, SS_RIGHT | SS_CENTERIMAGE, WS_EX_LEFT
|
||||
LTEXT "100%", IDC_SLIDER_DISPLAY00, 433, 67, 30, 9, SS_LEFT | SS_CENTERIMAGE, WS_EX_LEFT
|
||||
CONTROL "Sensitivity Slider", IDC_SLIDER00, TRACKBAR_CLASS, WS_TABSTOP | TBS_NOTICKS, 267, 77, 189, 11, WS_EX_LEFT
|
||||
RTEXT "Mouse Acceleration:", IDC_SLIDER_STATIC01, 329, 88, 100, 9, SS_RIGHT | SS_CENTERIMAGE, WS_EX_LEFT
|
||||
LTEXT "None", IDC_SLIDER_DISPLAY01, 433, 88, 30, 9, SS_LEFT | SS_CENTERIMAGE, WS_EX_LEFT
|
||||
CONTROL "Acceleration Slider", IDC_SLIDER01, TRACKBAR_CLASS, WS_TABSTOP | TBS_AUTOTICKS, 267, 98, 189, 11, WS_EX_LEFT
|
||||
RTEXT "Crosshair Movement:", IDC_SLIDER_STATIC02, 329, 111, 100, 9, SS_RIGHT | SS_CENTERIMAGE, WS_EX_LEFT
|
||||
LTEXT "100%", IDC_SLIDER_DISPLAY02, 433, 111, 30, 9, SS_LEFT | SS_CENTERIMAGE, WS_EX_LEFT
|
||||
CONTROL "Crosshair Slider", IDC_SLIDER02, TRACKBAR_CLASS, WS_TABSTOP | TBS_AUTOTICKS, 267, 120, 189, 11, WS_EX_LEFT
|
||||
AUTOCHECKBOX "Reverse Mouse Pitch", IDC_INVERTPITCH, 271, 134, 86, 17, WS_TABSTOP, WS_EX_LEFT
|
||||
AUTOCHECKBOX "Cursor Aiming (GE)", IDC_GECURSORAIMING, 369, 134, 83, 17, WS_TABSTOP, WS_EX_RIGHT
|
||||
AUTOCHECKBOX "Crouch Toggle", IDC_CROUCHTOGGLE, 271, 150, 65, 17, WS_TABSTOP, WS_EX_LEFT
|
||||
AUTOCHECKBOX "Cursor Aiming (PD)", IDC_PDCURSORAIMING, 369, 150, 83, 17, WS_TABSTOP, WS_EX_RIGHT
|
||||
GROUPBOX "All Players", IDC_ALLPLAYERS, 271, 168, 181, 75, 0, WS_EX_RIGHT
|
||||
LTEXT "16 x 9 Ratio Override:", IDC_RATIOSTATIC, 279, 179, 76, 9, SS_LEFT, WS_EX_LEFT
|
||||
EDITTEXT IDC_RATIOWIDTH, 398, 178, 15, 12, ES_CENTER | ES_AUTOHSCROLL | ES_NUMBER, WS_EX_LEFT
|
||||
CTEXT "x", IDC_RATIOSTATICX, 417, 179, 8, 9, SS_LEFT | SS_CENTER, WS_EX_LEFT
|
||||
EDITTEXT IDC_RATIOHEIGHT, 428, 178, 15, 12, ES_CENTER | ES_AUTOHSCROLL | ES_NUMBER, WS_EX_LEFT
|
||||
PUSHBUTTON "Reset FOV", IDC_RESETFOV, 278, 192, 40, 9, WS_TABSTOP, WS_EX_RIGHT
|
||||
LTEXT "Vertical FOV: 60 (Hor 91)", IDC_FOV_DEGREES, 358, 192, 93, 9, SS_LEFT | SS_CENTERIMAGE | SS_NOTIFY, WS_EX_LEFT
|
||||
CONTROL "Field of View Slider", IDC_FOV, TRACKBAR_CLASS, WS_TABSTOP | TBS_NOTICKS, 274, 202, 175, 14, WS_EX_LEFT
|
||||
LTEXT "Default FOV", IDC_FOV_NOTE, 279, 217, 80, 8, SS_LEFT | SS_NOTIFY, WS_EX_LEFT
|
||||
AUTOCHECKBOX "Show Crosshair (GE)", IDC_GESHOWCROSSHAIR, 363, 217, 81, 8, WS_TABSTOP, WS_EX_RIGHT
|
||||
AUTOCHECKBOX "Bypass ViewModel Position Fix For FOV Override", IDC_BYPASSVIEWMODELFOVWEAK, 275, 229, 169, 9, WS_TABSTOP, WS_EX_RIGHT
|
||||
GROUPBOX "Info", IDC_INFOBOX, 271, 245, 181, 66, NOT WS_TABSTOP, WS_EX_RIGHT
|
||||
CTEXT "For multiplayer, connect multiple mice/keyboards and restart 1964, then select the device per player.\r\n\r\nIf you wish to use a USB controller, change the input plugin to N-Rage Or DirectInput.", IDC_INFO, 274, 259, 176, 41, NOT WS_GROUP | SS_CENTER, WS_EX_TRANSPARENT
|
||||
PUSHBUTTON "Revert", IDC_REVERT, 298, 317, 60, 14, WS_TABSTOP, WS_EX_LEFT
|
||||
PUSHBUTTON "Clear", IDC_CLEAR, 364, 317, 60, 14, WS_TABSTOP, WS_EX_LEFT
|
||||
CTEXT "", IDC_PARTITION, 7, 337, 456, 2, SS_CENTER | SS_SUNKEN, WS_EX_LEFT
|
||||
RTEXT "Toggle Injection", IDC_LOCK_LABEL, 17, 347, 70, 15, SS_RIGHT | SS_CENTERIMAGE, WS_EX_TRANSPARENT
|
||||
PUSHBUTTON "Lock", IDC_LOCK, 97, 347, 70, 14, WS_GROUP | BS_FLAT, WS_EX_LEFT
|
||||
AUTOCHECKBOX "Autolock Mouse", IDC_LOCKONFOCUS, 177, 344, 110, 8, WS_TABSTOP, WS_EX_LEFT
|
||||
AUTOCHECKBOX "Unlock Mouse on Window Loss", IDC_UNLOCKONWINLOSS, 177, 355, 110, 10, WS_TABSTOP, WS_EX_LEFT
|
||||
DEFPUSHBUTTON "OK", IDC_OK, 293, 347, 50, 14, 0, WS_EX_LEFT
|
||||
PUSHBUTTON "Cancel", IDC_CANCEL, 353, 347, 50, 14, 0, WS_EX_LEFT
|
||||
PUSHBUTTON "Help", IDC_HELPPOPUP, 413, 347, 50, 14, 0, WS_EX_LEFT
|
||||
}
|
||||
|
||||
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
|
||||
1 VERSIONINFO
|
||||
FILEVERSION 2,3,0,0
|
||||
PRODUCTVERSION 2,3,0,0
|
||||
FILEOS VOS_NT_WINDOWS32
|
||||
FILETYPE VFT_DLL
|
||||
FILESUBTYPE VFT2_UNKNOWN
|
||||
FILEFLAGSMASK 0
|
||||
FILEFLAGS 0
|
||||
{
|
||||
BLOCK "StringFileInfo"
|
||||
{
|
||||
BLOCK "040904B0"
|
||||
{
|
||||
VALUE "FileDescription", "Mouse Injector for 1964"
|
||||
VALUE "FileVersion", "2, 3, 0, 0"
|
||||
VALUE "InternalName", "Mouse Injector"
|
||||
VALUE "LegalCopyright", "Copyright (C) 2021 Carnivorous"
|
||||
VALUE "OriginalFilename", "Mouse_Injector.dll"
|
||||
VALUE "ProductName", "Mouse Injector for GE/PD"
|
||||
VALUE "ProductVersion", "2, 3, 0, 0"
|
||||
}
|
||||
}
|
||||
BLOCK "VarFileInfo"
|
||||
{
|
||||
VALUE "Translation", 0x0409, 0x04B0
|
||||
}
|
||||
}
|
||||
@@ -1,538 +0,0 @@
|
||||
//==========================================================================
|
||||
// Mouse Injector Plugin
|
||||
//==========================================================================
|
||||
// Copyright (C) 2016-2021 Carnivorous
|
||||
// All rights reserved.
|
||||
//
|
||||
// Mouse Injector 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, visit http://www.gnu.org/licenses/gpl-2.0.html
|
||||
//==========================================================================
|
||||
// Virtual Keys, Standard Set
|
||||
#define VK_LBUTTON 0x01
|
||||
#define VK_RBUTTON 0x02
|
||||
#define VK_CANCEL 0x03
|
||||
#define VK_MBUTTON 0x04 // NOT contiguous with L & RBUTTON
|
||||
|
||||
#if(_WIN32_WINNT >= 0x0500)
|
||||
#define VK_XBUTTON1 0x05 // NOT contiguous with L & RBUTTON
|
||||
#define VK_XBUTTON2 0x06 // NOT contiguous with L & RBUTTON
|
||||
#endif
|
||||
|
||||
// 0x07 : unassigned
|
||||
|
||||
#define VK_BACK 0x08
|
||||
#define VK_TAB 0x09
|
||||
|
||||
// 0x0A - 0x0B : mouse wheel
|
||||
#define VK_WHEELUP 0x0A // THERE IS NO SUCH THING AS VK_WHEELUP - I INVENTED THIS BECAUSE I'M LAZY - TERRIBLE HACK
|
||||
#define VK_WHEELDOWN 0x0B // THERE IS NO SUCH THING AS VK_WHEELDOWN - I INVENTED THIS BECAUSE I'M LAZY - TERRIBLE HACK
|
||||
|
||||
#define VK_CLEAR 0x0C
|
||||
#define VK_RETURN 0x0D
|
||||
|
||||
#define VK_WHEELLEFT 0x0F // THERE IS NO SUCH THING AS VK_WHEELLEFT - I INVENTED THIS BECAUSE I'M LAZY - TERRIBLE HACK
|
||||
#define VK_WHEELRIGHT 0x0E // THERE IS NO SUCH THING AS VK_WHEELRIGHT - I INVENTED THIS BECAUSE I'M LAZY - TERRIBLE HACK
|
||||
|
||||
#define VK_SHIFT 0x10
|
||||
#define VK_CONTROL 0x11
|
||||
#define VK_MENU 0x12
|
||||
#define VK_PAUSE 0x13
|
||||
#define VK_CAPITAL 0x14
|
||||
|
||||
#define VK_KANA 0x15
|
||||
#define VK_HANGEUL 0x15 // old name - should be here for compatibility
|
||||
#define VK_HANGUL 0x15
|
||||
#define VK_JUNJA 0x17
|
||||
#define VK_FINAL 0x18
|
||||
#define VK_HANJA 0x19
|
||||
#define VK_KANJI 0x19
|
||||
|
||||
#define VK_ESCAPE 0x1B
|
||||
|
||||
#define VK_CONVERT 0x1C
|
||||
#define VK_NONCONVERT 0x1D
|
||||
#define VK_ACCEPT 0x1E
|
||||
#define VK_MODECHANGE 0x1F
|
||||
|
||||
#define VK_SPACE 0x20
|
||||
#define VK_PRIOR 0x21
|
||||
#define VK_NEXT 0x22
|
||||
#define VK_END 0x23
|
||||
#define VK_HOME 0x24
|
||||
#define VK_LEFT 0x25
|
||||
#define VK_UP 0x26
|
||||
#define VK_RIGHT 0x27
|
||||
#define VK_DOWN 0x28
|
||||
#define VK_SELECT 0x29
|
||||
#define VK_PRINT 0x2A
|
||||
#define VK_EXECUTE 0x2B
|
||||
#define VK_SNAPSHOT 0x2C
|
||||
#define VK_INSERT 0x2D
|
||||
#define VK_DELETE 0x2E
|
||||
#define VK_HELP 0x2F
|
||||
|
||||
// VK_0 - VK_9 are the same as ASCII '0' - '9' (0x30 - 0x39)
|
||||
// 0x40 : unassigned
|
||||
// VK_A - VK_Z are the same as ASCII 'A' - 'Z' (0x41 - 0x5A)
|
||||
|
||||
#define VK_LWIN 0x5B
|
||||
#define VK_RWIN 0x5C
|
||||
#define VK_APPS 0x5D
|
||||
|
||||
// 0x5E : reserved
|
||||
|
||||
#define VK_SLEEP 0x5F
|
||||
|
||||
#define VK_NUMPAD0 0x60
|
||||
#define VK_NUMPAD1 0x61
|
||||
#define VK_NUMPAD2 0x62
|
||||
#define VK_NUMPAD3 0x63
|
||||
#define VK_NUMPAD4 0x64
|
||||
#define VK_NUMPAD5 0x65
|
||||
#define VK_NUMPAD6 0x66
|
||||
#define VK_NUMPAD7 0x67
|
||||
#define VK_NUMPAD8 0x68
|
||||
#define VK_NUMPAD9 0x69
|
||||
#define VK_MULTIPLY 0x6A
|
||||
#define VK_ADD 0x6B
|
||||
#define VK_SEPARATOR 0x6C
|
||||
#define VK_SUBTRACT 0x6D
|
||||
#define VK_DECIMAL 0x6E
|
||||
#define VK_DIVIDE 0x6F
|
||||
#define VK_F1 0x70
|
||||
#define VK_F2 0x71
|
||||
#define VK_F3 0x72
|
||||
#define VK_F4 0x73
|
||||
#define VK_F5 0x74
|
||||
#define VK_F6 0x75
|
||||
#define VK_F7 0x76
|
||||
#define VK_F8 0x77
|
||||
#define VK_F9 0x78
|
||||
#define VK_F10 0x79
|
||||
#define VK_F11 0x7A
|
||||
#define VK_F12 0x7B
|
||||
#define VK_F13 0x7C
|
||||
#define VK_F14 0x7D
|
||||
#define VK_F15 0x7E
|
||||
#define VK_F16 0x7F
|
||||
#define VK_F17 0x80
|
||||
#define VK_F18 0x81
|
||||
#define VK_F19 0x82
|
||||
#define VK_F20 0x83
|
||||
#define VK_F21 0x84
|
||||
#define VK_F22 0x85
|
||||
#define VK_F23 0x86
|
||||
#define VK_F24 0x87
|
||||
|
||||
// 0x88 - 0x8F : unassigned
|
||||
|
||||
#define VK_NUMLOCK 0x90
|
||||
#define VK_SCROLL 0x91
|
||||
|
||||
// NEC PC-9800 kbd definitions
|
||||
#define VK_OEM_NEC_EQUAL 0x92 // '=' key on numpad
|
||||
|
||||
// Fujitsu/OASYS kbd definitions
|
||||
#define VK_OEM_FJ_JISHO 0x92 // 'Dictionary' key
|
||||
#define VK_OEM_FJ_MASSHOU 0x93 // 'Unregister word' key
|
||||
#define VK_OEM_FJ_TOUROKU 0x94 // 'Register word' key
|
||||
#define VK_OEM_FJ_LOYA 0x95 // 'Left OYAYUBI' key
|
||||
#define VK_OEM_FJ_ROYA 0x96 // 'Right OYAYUBI' key
|
||||
|
||||
// 0x97 - 0x9F : unassigned
|
||||
|
||||
// VK_L* & VK_R* - left and right Alt, Ctrl and Shift virtual keys.
|
||||
// Used only as parameters to GetAsyncKeyState() and GetKeyState().
|
||||
// No other API or message will distinguish left and right keys in this way.
|
||||
#define VK_LSHIFT 0xA0
|
||||
#define VK_RSHIFT 0xA1
|
||||
#define VK_LCONTROL 0xA2
|
||||
#define VK_RCONTROL 0xA3
|
||||
#define VK_LMENU 0xA4
|
||||
#define VK_RMENU 0xA5
|
||||
|
||||
#if(_WIN32_WINNT >= 0x0500)
|
||||
#define VK_BROWSER_BACK 0xA6
|
||||
#define VK_BROWSER_FORWARD 0xA7
|
||||
#define VK_BROWSER_REFRESH 0xA8
|
||||
#define VK_BROWSER_STOP 0xA9
|
||||
#define VK_BROWSER_SEARCH 0xAA
|
||||
#define VK_BROWSER_FAVORITES 0xAB
|
||||
#define VK_BROWSER_HOME 0xAC
|
||||
|
||||
#define VK_VOLUME_MUTE 0xAD
|
||||
#define VK_VOLUME_DOWN 0xAE
|
||||
#define VK_VOLUME_UP 0xAF
|
||||
#define VK_MEDIA_NEXT_TRACK 0xB0
|
||||
#define VK_MEDIA_PREV_TRACK 0xB1
|
||||
#define VK_MEDIA_STOP 0xB2
|
||||
#define VK_MEDIA_PLAY_PAUSE 0xB3
|
||||
#define VK_LAUNCH_MAIL 0xB4
|
||||
#define VK_LAUNCH_MEDIA_SELECT 0xB5
|
||||
#define VK_LAUNCH_APP1 0xB6
|
||||
#define VK_LAUNCH_APP2 0xB7
|
||||
|
||||
#endif
|
||||
|
||||
// 0xB8 - 0xB9 : reserved
|
||||
|
||||
#define VK_OEM_1 0xBA // ';:' for US
|
||||
#define VK_OEM_PLUS 0xBB // '+' any country
|
||||
#define VK_OEM_COMMA 0xBC // ',' any country
|
||||
#define VK_OEM_MINUS 0xBD // '-' any country
|
||||
#define VK_OEM_PERIOD 0xBE // '.' any country
|
||||
#define VK_OEM_2 0xBF // '/?' for US
|
||||
#define VK_OEM_3 0xC0 // '`~' for US
|
||||
|
||||
|
||||
// 0xC1 - 0xD7 : reserved
|
||||
|
||||
// 0xD8 - 0xDA : unassigned
|
||||
|
||||
#define VK_OEM_4 0xDB // '[{' for US
|
||||
#define VK_OEM_5 0xDC // '\|' for US
|
||||
#define VK_OEM_6 0xDD // ']}' for US
|
||||
#define VK_OEM_7 0xDE // ''"' for US
|
||||
#define VK_OEM_8 0xDF
|
||||
|
||||
// 0xE0 : reserved
|
||||
|
||||
|
||||
// Various extended or enhanced keyboards
|
||||
|
||||
#define VK_OEM_AX 0xE1 // 'AX' key on Japanese AX kbd
|
||||
#define VK_OEM_102 0xE2 // "<>" or "\|" on RT 102-key kbd.
|
||||
#define VK_ICO_HELP 0xE3 // Help key on ICO
|
||||
#define VK_ICO_00 0xE4 // 00 key on ICO
|
||||
|
||||
#if(WINVER >= 0x0400)
|
||||
#define VK_PROCESSKEY 0xE5
|
||||
#endif
|
||||
|
||||
#define VK_ICO_CLEAR 0xE6
|
||||
|
||||
|
||||
#if(_WIN32_WINNT >= 0x0500)
|
||||
#define VK_PACKET 0xE7
|
||||
#endif
|
||||
|
||||
// 0xE8 : unassigned
|
||||
|
||||
|
||||
// Nokia/Ericsson definitions
|
||||
#define VK_OEM_RESET 0xE9
|
||||
#define VK_OEM_JUMP 0xEA
|
||||
#define VK_OEM_PA1 0xEB
|
||||
#define VK_OEM_PA2 0xEC
|
||||
#define VK_OEM_PA3 0xED
|
||||
#define VK_OEM_WSCTRL 0xEE
|
||||
#define VK_OEM_CUSEL 0xEF
|
||||
#define VK_OEM_ATTN 0xF0
|
||||
#define VK_OEM_FINISH 0xF1
|
||||
#define VK_OEM_COPY 0xF2
|
||||
#define VK_OEM_AUTO 0xF3
|
||||
#define VK_OEM_ENLW 0xF4
|
||||
#define VK_OEM_BACKTAB 0xF5
|
||||
|
||||
#define VK_ATTN 0xF6
|
||||
#define VK_CRSEL 0xF7
|
||||
#define VK_EXSEL 0xF8
|
||||
#define VK_EREOF 0xF9
|
||||
#define VK_PLAY 0xFA
|
||||
#define VK_ZOOM 0xFB
|
||||
#define VK_NONAME 0xFC
|
||||
#define VK_PA1 0xFD
|
||||
#define VK_OEM_CLEAR 0xFE
|
||||
|
||||
// 0xFF : reserved
|
||||
|
||||
struct VKeyInfo
|
||||
{
|
||||
unsigned int VKey;
|
||||
LPCSTR VKname;
|
||||
};
|
||||
|
||||
#define AddVKey(VK, VKName) {(VK), (VKName)}
|
||||
|
||||
static struct VKeyInfo vkis[] =
|
||||
{
|
||||
AddVKey(0x00, "None"), // THERE IS NO SUCH THING AS 0x00 - I INVENTED THIS BECAUSE I'M LAZY - TERRIBLE HACK
|
||||
AddVKey(VK_LBUTTON, "Left Mouse Button"),
|
||||
AddVKey(VK_RBUTTON, "Right Mouse Button"),
|
||||
AddVKey(VK_CANCEL, "Control-Break"),
|
||||
AddVKey(0x04, "Middle Mouse Button"),
|
||||
AddVKey(0x05, "X1 Mouse Button"),
|
||||
AddVKey(0x06, "X2 Mouse Button"),
|
||||
AddVKey(0x07, "Undefined"),
|
||||
AddVKey(VK_BACK, "Backspace"),
|
||||
AddVKey(VK_TAB, "Tab"),
|
||||
AddVKey(0x0A, "Mouse Wheel Up"), // THERE IS NO SUCH THING AS VK_WHEELUP - I INVENTED THIS BECAUSE I'M LAZY - TERRIBLE HACK
|
||||
AddVKey(0x0B, "Mouse Wheel Down"), // THERE IS NO SUCH THING AS VK_WHEELDOWN - I INVENTED THIS BECAUSE I'M LAZY - TERRIBLE HACK
|
||||
AddVKey(VK_CLEAR, "Clear"),
|
||||
AddVKey(VK_RETURN, "Enter"),
|
||||
AddVKey(0x0E, "Mouse Wheel Left"), // THERE IS NO SUCH THING AS VK_WHEELLEFT - I INVENTED THIS BECAUSE I'M LAZY - TERRIBLE HACK
|
||||
AddVKey(0x0F, "Mouse Wheel Right"), // THERE IS NO SUCH THING AS VK_WHEELRIGHT - I INVENTED THIS BECAUSE I'M LAZY - TERRIBLE HACK
|
||||
AddVKey(VK_SHIFT, "Shift"),
|
||||
AddVKey(VK_CONTROL, "Control"),
|
||||
AddVKey(VK_MENU, "Alt"),
|
||||
AddVKey(VK_PAUSE, "Pause"),
|
||||
AddVKey(VK_CAPITAL, "Caps Lock"),
|
||||
AddVKey(VK_KANA, "IME Kana"), // Input Method Editor (IME) Kana mode
|
||||
AddVKey(VK_HANGUL, "IME Hangul"),
|
||||
AddVKey(0x16, "Undefined"),
|
||||
AddVKey(VK_JUNJA, "IME Junja"),
|
||||
AddVKey(VK_FINAL, "IME final"),
|
||||
AddVKey(VK_HANJA, "IME Hanja"),
|
||||
AddVKey(VK_KANJI, "IME Kanji"),
|
||||
AddVKey(0x1A, "Undefined"),
|
||||
AddVKey(VK_ESCAPE, "Escape"),
|
||||
AddVKey(VK_CONVERT, "IME Convert"),
|
||||
AddVKey(VK_NONCONVERT, "IME Non-Convert"),
|
||||
AddVKey(VK_ACCEPT, "IME Accept"),
|
||||
AddVKey(VK_MODECHANGE, "IME Mode Change"),
|
||||
AddVKey(VK_SPACE, "Spacebar"),
|
||||
AddVKey(VK_PRIOR, "Page Up"),
|
||||
AddVKey(VK_NEXT, "Page Down"),
|
||||
AddVKey(VK_END, "End"),
|
||||
AddVKey(VK_HOME, "Home"),
|
||||
AddVKey(VK_LEFT, "Left Arrow"),
|
||||
AddVKey(VK_UP, "Up Arrow"),
|
||||
AddVKey(VK_RIGHT, "Right Arrow"),
|
||||
AddVKey(VK_DOWN, "Down Arrow"),
|
||||
AddVKey(VK_SELECT, "Select"),
|
||||
AddVKey(VK_PRINT, "Print"),
|
||||
AddVKey(VK_EXECUTE, "Execute"),
|
||||
AddVKey(VK_SNAPSHOT, "Print Screen"),
|
||||
AddVKey(VK_INSERT, "Insert"),
|
||||
AddVKey(VK_DELETE, "Delete"),
|
||||
AddVKey(VK_HELP, "Help"),
|
||||
AddVKey(0x30, "0"),
|
||||
AddVKey(0x31, "1"),
|
||||
AddVKey(0x32, "2"),
|
||||
AddVKey(0x33, "3"),
|
||||
AddVKey(0x34, "4"),
|
||||
AddVKey(0x35, "5"),
|
||||
AddVKey(0x36, "6"),
|
||||
AddVKey(0x37, "7"),
|
||||
AddVKey(0x38, "8"),
|
||||
AddVKey(0x39, "9"),
|
||||
AddVKey(0x3A, "Undefined"),
|
||||
AddVKey(0x3B, "Undefined"),
|
||||
AddVKey(0x3C, "Undefined"),
|
||||
AddVKey(0x3D, "Undefined"),
|
||||
AddVKey(0x3E, "Undefined"),
|
||||
AddVKey(0x3F, "Undefined"),
|
||||
AddVKey(0x40, "Undefined"),
|
||||
AddVKey(0x41, "A"),
|
||||
AddVKey(0x42, "B"),
|
||||
AddVKey(0x43, "C"),
|
||||
AddVKey(0x44, "D"),
|
||||
AddVKey(0x45, "E"),
|
||||
AddVKey(0x46, "F"),
|
||||
AddVKey(0x47, "G"),
|
||||
AddVKey(0x48, "H"),
|
||||
AddVKey(0x49, "I"),
|
||||
AddVKey(0x4A, "J"),
|
||||
AddVKey(0x4B, "K"),
|
||||
AddVKey(0x4C, "L"),
|
||||
AddVKey(0x4D, "M"),
|
||||
AddVKey(0x4E, "N"),
|
||||
AddVKey(0x4F, "O"),
|
||||
AddVKey(0x50, "P"),
|
||||
AddVKey(0x51, "Q"),
|
||||
AddVKey(0x52, "R"),
|
||||
AddVKey(0x53, "S"),
|
||||
AddVKey(0x54, "T"),
|
||||
AddVKey(0x55, "U"),
|
||||
AddVKey(0x56, "V"),
|
||||
AddVKey(0x57, "W"),
|
||||
AddVKey(0x58, "X"),
|
||||
AddVKey(0x59, "Y"),
|
||||
AddVKey(0x5A, "Z"),
|
||||
|
||||
AddVKey(VK_LWIN, "Left Windows"), // Left Windows key (Microsoft Natural keyboard)
|
||||
AddVKey(VK_RWIN, "Right Windows"), // Right Windows key (Natural keyboard)
|
||||
AddVKey(VK_APPS, "App"), // Applications key (Natural keyboard)
|
||||
AddVKey(0x5E, "Reserved"),
|
||||
AddVKey(VK_SLEEP, "Sleep"),
|
||||
AddVKey(VK_NUMPAD0, "Numpad #0"),
|
||||
AddVKey(VK_NUMPAD1, "Numpad #1"),
|
||||
AddVKey(VK_NUMPAD2, "Numpad #2"),
|
||||
AddVKey(VK_NUMPAD3, "Numpad #3"),
|
||||
AddVKey(VK_NUMPAD4, "Numpad #4"),
|
||||
AddVKey(VK_NUMPAD5, "Numpad #5"),
|
||||
AddVKey(VK_NUMPAD6, "Numpad #6"),
|
||||
AddVKey(VK_NUMPAD7, "Numpad #7"),
|
||||
AddVKey(VK_NUMPAD8, "Numpad #8"),
|
||||
AddVKey(VK_NUMPAD9, "Numpad #9"),
|
||||
AddVKey(VK_MULTIPLY, "Numpad *"),
|
||||
AddVKey(VK_ADD, "Numpad +"),
|
||||
AddVKey(VK_SEPARATOR, "Separator"),
|
||||
AddVKey(VK_SUBTRACT, "Numpad -"),
|
||||
AddVKey(VK_DECIMAL, "Numpad ."),
|
||||
AddVKey(VK_DIVIDE, "Numpad /"),
|
||||
AddVKey(VK_F1, "F1"),
|
||||
AddVKey(VK_F2, "F2"),
|
||||
AddVKey(VK_F3, "F3"),
|
||||
AddVKey(VK_F4, "F4"),
|
||||
AddVKey(VK_F5, "F5"),
|
||||
AddVKey(VK_F6, "F6"),
|
||||
AddVKey(VK_F7, "F7"),
|
||||
AddVKey(VK_F8, "F8"),
|
||||
AddVKey(VK_F9, "F9"),
|
||||
AddVKey(VK_F10, "F10"),
|
||||
AddVKey(VK_F11, "F11"),
|
||||
AddVKey(VK_F12, "F12"),
|
||||
AddVKey(VK_F13, "F13"),
|
||||
AddVKey(VK_F14, "F14"),
|
||||
AddVKey(VK_F15, "F15"),
|
||||
AddVKey(VK_F16, "F16"),
|
||||
AddVKey(VK_F17, "F17"),
|
||||
AddVKey(VK_F18, "F18"),
|
||||
AddVKey(VK_F19, "F19"),
|
||||
AddVKey(VK_F20, "F20"),
|
||||
AddVKey(VK_F21, "F21"),
|
||||
AddVKey(VK_F22, "F22"),
|
||||
AddVKey(VK_F23, "F23"),
|
||||
AddVKey(VK_F24, "F24"),
|
||||
AddVKey(0x88, "Unassigned"),
|
||||
AddVKey(0x89, "Unassigned"),
|
||||
AddVKey(0x8A, "Unassigned"),
|
||||
AddVKey(0x8B, "Unassigned"),
|
||||
AddVKey(0x8C, "Unassigned"),
|
||||
AddVKey(0x8D, "Unassigned"),
|
||||
AddVKey(0x8E, "Unassigned"),
|
||||
AddVKey(0x8F, "Unassigned"),
|
||||
AddVKey(VK_NUMLOCK, "Num Lock"),
|
||||
AddVKey(VK_SCROLL, "Scroll Lock"),
|
||||
AddVKey(0x92, "OEM specific"),
|
||||
AddVKey(0x93, "OEM specific"),
|
||||
AddVKey(0x94, "OEM specific"),
|
||||
AddVKey(0x95, "OEM specific"),
|
||||
AddVKey(0x96, "OEM specific"),
|
||||
AddVKey(0x97, "Unassigned"),
|
||||
AddVKey(0x98, "Unassigned"),
|
||||
AddVKey(0x99, "Unassigned"),
|
||||
AddVKey(0x9A, "Unassigned"),
|
||||
AddVKey(0x9B, "Unassigned"),
|
||||
AddVKey(0x9C, "Unassigned"),
|
||||
AddVKey(0x9D, "Unassigned"),
|
||||
AddVKey(0x9E, "Unassigned"),
|
||||
AddVKey(0x9F, "Unassigned"),
|
||||
AddVKey(VK_LSHIFT, "Left Shift"),
|
||||
AddVKey(VK_RSHIFT, "Right Shift"),
|
||||
AddVKey(VK_LCONTROL, "Left Control"),
|
||||
AddVKey(VK_RCONTROL, "Right Control"),
|
||||
AddVKey(VK_LMENU, "Left Alt"),
|
||||
AddVKey(VK_RMENU, "Right Alt"),
|
||||
AddVKey(0xA6, "Browser Back"), // Windows 2000/XP: Browser Back key
|
||||
AddVKey(0xA7, "Browser Forward"), // Windows 2000/XP: Browser Forward key
|
||||
AddVKey(0xA8, "Browser Refresh"), // Windows 2000/XP: Browser Refresh key
|
||||
AddVKey(0xA9, "Browser Stop"), // Windows 2000/XP: Browser Stop key
|
||||
AddVKey(0xAA, "Browser Search"), // Windows 2000/XP: Browser Search key
|
||||
AddVKey(0xAB, "Browser Favorites"), // Windows 2000/XP: Browser Favorites key
|
||||
AddVKey(0xAC, "Browser Start/Home"), // Windows 2000/XP: Browser Start and Home key
|
||||
AddVKey(0xAD, "Volume Mute"), // Windows 2000/XP: Volume Mute key
|
||||
AddVKey(0xAE, "Volume Down"), // Windows 2000/XP: Volume Down key
|
||||
AddVKey(0xAF, "Volume Up"), // Windows 2000/XP: Volume Up key
|
||||
AddVKey(0xB0, "Next Track"), // Windows 2000/XP: Next Track key
|
||||
AddVKey(0xB1, "Previous Track"), // Windows 2000/XP: Previous Track key
|
||||
AddVKey(0xB2, "Stop Track"), // Windows 2000/XP: Stop Media key
|
||||
AddVKey(0xB3, "Play/Pause Track"), // Windows 2000/XP: Play/Pause Media key
|
||||
AddVKey(0xB4, "E-Mail"), // Windows 2000/XP: Start Mail key
|
||||
AddVKey(0xB5, "Select Track"), // Windows 2000/XP: Select Media key
|
||||
AddVKey(0xB6, "Start App 1"), // Windows 2000/XP: Start Application 1 key
|
||||
AddVKey(0xB7, "Start App 2"), // Windows 2000/XP: Start Application 2 key
|
||||
AddVKey(0xB8, "Reserved"),
|
||||
AddVKey(0xB9, "Reserved"),
|
||||
AddVKey(VK_OEM_1, ":"), // Used for miscellaneous characters; it can vary by keyboard." "Windows 2000/XP: For the US standard keyboard, the \';:\' key
|
||||
AddVKey(VK_OEM_PLUS, "+"), // Windows 2000/XP: For any country/region, the \'+\' key
|
||||
AddVKey(VK_OEM_COMMA, ","), // Windows 2000/XP: For any country/region, the \',\' key
|
||||
AddVKey(VK_OEM_MINUS, "-"), // Windows 2000/XP: For any country/region, the \'-\' key
|
||||
AddVKey(VK_OEM_PERIOD, "."), // Windows 2000/XP: For any country/region, the \'.\' key
|
||||
AddVKey(VK_OEM_2, "?"), // Used for miscellaneous characters; it can vary by keyboard." "Windows 2000/XP: For the US standard keyboard, the \'/?\' key
|
||||
AddVKey(VK_OEM_3, "~"), // Used for miscellaneous characters; it can vary by keyboard." "Windows 2000/XP: For the US standard keyboard, the \'`~\' key
|
||||
AddVKey(0xC1, "Reserved"),
|
||||
AddVKey(0xC2, "Reserved"),
|
||||
AddVKey(0xC3, "Reserved"),
|
||||
AddVKey(0xC4, "Reserved"),
|
||||
AddVKey(0xC5, "Reserved"),
|
||||
AddVKey(0xC6, "Reserved"),
|
||||
AddVKey(0xC7, "Reserved"),
|
||||
AddVKey(0xC8, "Reserved"),
|
||||
AddVKey(0xC9, "Reserved"),
|
||||
AddVKey(0xCA, "Reserved"),
|
||||
AddVKey(0xCB, "Reserved"),
|
||||
AddVKey(0xCC, "Reserved"),
|
||||
AddVKey(0xCD, "Reserved"),
|
||||
AddVKey(0xCE, "Reserved"),
|
||||
AddVKey(0xCF, "Reserved"),
|
||||
AddVKey(0xD0, "Reserved"),
|
||||
AddVKey(0xD1, "Reserved"),
|
||||
AddVKey(0xD2, "Reserved"),
|
||||
AddVKey(0xD3, "Reserved"),
|
||||
AddVKey(0xD4, "Reserved"),
|
||||
AddVKey(0xD5, "Reserved"),
|
||||
AddVKey(0xD6, "Reserved"),
|
||||
AddVKey(0xD7, "Reserved"),
|
||||
AddVKey(0xD8, "Unassigned"),
|
||||
AddVKey(0xD9, "Unassigned"),
|
||||
AddVKey(0xDA, "Unassigned"),
|
||||
AddVKey(VK_OEM_4, "["), // Used for miscellaneous characters; it can vary by keyboard." "Windows 2000/XP: For the US standard keyboard, the \'[{\' key
|
||||
AddVKey(VK_OEM_5, "\\"), // Used for miscellaneous characters; it can vary by keyboard." "Windows 2000/XP: For the US standard keyboard, the \'\\|\' key
|
||||
AddVKey(VK_OEM_6, "]"), // Used for miscellaneous characters; it can vary by keyboard." "Windows 2000/XP: For the US standard keyboard, the \']}\' key
|
||||
AddVKey(VK_OEM_7, "'"), // Used for miscellaneous characters; it can vary by keyboard." "Windows 2000/XP: For the US standard keyboard, the \'single-quote/double-quote\' key
|
||||
|
||||
AddVKey(VK_OEM_8, "OEM Misc"), // Used for miscellaneous characters; it can vary by keyboard.
|
||||
AddVKey(0xE0, "Reserved"),
|
||||
AddVKey(0xE1, "OEM Specific"),
|
||||
AddVKey(VK_OEM_102, "Angle Bracket"), // Windows 2000/XP: Either the angle bracket key or the backslash key on the RT 102-key keyboard
|
||||
AddVKey(0xE3, "OEM Specific"),
|
||||
AddVKey(0xE4, "OEM Specific"),
|
||||
AddVKey(VK_PROCESSKEY, "IME Process"), // Windows 95/98/Me, Windows NT 4.0, Windows 2000/XP: IME PROCESS key
|
||||
AddVKey(0xE6, "OEM Specific"),
|
||||
AddVKey(0xE7, "Packet"), // Windows 2000/XP: Used to pass Unicode characters as if they were keystrokes. The VK_PACKET key is the low word of a 32-bit Virtual Key value used for non-keyboard input methods. For more information, see Remark in KEYBDINPUT, SendInput, WM_KEYDOWN, and WM_KEYUP
|
||||
AddVKey(0xE8, "Unassigned"),
|
||||
AddVKey(0xE9, "OEM Specific"),
|
||||
AddVKey(0xEA, "OEM Specific"),
|
||||
AddVKey(0xEB, "OEM Specific"),
|
||||
AddVKey(0xEC, "OEM Specific"),
|
||||
AddVKey(0xED, "OEM Specific"),
|
||||
AddVKey(0xEF, "OEM Specific"),
|
||||
AddVKey(0xF0, "OEM Specific"),
|
||||
AddVKey(0xF1, "OEM Specific"),
|
||||
AddVKey(0xF2, "OEM Specific"),
|
||||
AddVKey(0xF3, "OEM Specific"),
|
||||
AddVKey(0xF4, "OEM Specific"),
|
||||
AddVKey(0xF5, "OEM Specific"),
|
||||
AddVKey(VK_ATTN, "Attn"),
|
||||
AddVKey(VK_CRSEL, "CrSel"),
|
||||
AddVKey(VK_EXSEL, "ExSel"),
|
||||
AddVKey(VK_EREOF, "Erase"),
|
||||
AddVKey(VK_PLAY, "Play"),
|
||||
AddVKey(VK_ZOOM, "Zoom"),
|
||||
AddVKey(VK_NONAME, "No Name"),
|
||||
AddVKey(VK_PA1, "Pa1"),
|
||||
AddVKey(VK_OEM_CLEAR, "Clear"),
|
||||
AddVKey(0xFF, "Invalid Key")
|
||||
};
|
||||
|
||||
static LPCSTR GetKeyName(unsigned int VKey)
|
||||
{
|
||||
for(unsigned int i = 0; i < ARRAY_SIZE(vkis); i++)
|
||||
{
|
||||
if(VKey == vkis[i].VKey)
|
||||
return vkis[i].VKname;
|
||||
}
|
||||
return vkis[0xFF].VKname; // return "Invalid Key"
|
||||
}
|
||||
Reference in new issue
Block a user