mirror of
https://github.com/open-goal/jak-project
synced 2026-07-08 06:30:44 -04:00
implement cpad stuff
This commit is contained in:
@@ -34,6 +34,7 @@ set(RUNTIME_SOURCE
|
||||
system/IOP_Kernel.cpp
|
||||
system/iop_thread.cpp
|
||||
system/Deci2Server.cpp
|
||||
system/newpad.cpp
|
||||
sce/libcdvd_ee.cpp
|
||||
sce/libscf.cpp
|
||||
sce/libdma.cpp
|
||||
|
||||
@@ -8,9 +8,11 @@
|
||||
|
||||
#include "common/log/log.h"
|
||||
|
||||
/* ****************************** */
|
||||
/* Internal functions */
|
||||
/* ****************************** */
|
||||
/*
|
||||
********************************
|
||||
* Internal functions
|
||||
********************************
|
||||
*/
|
||||
|
||||
namespace {
|
||||
|
||||
@@ -28,9 +30,11 @@ void set_main_display(std::shared_ptr<GfxDisplay> display) {
|
||||
|
||||
} // namespace
|
||||
|
||||
/* ****************************** */
|
||||
/* GfxDisplay */
|
||||
/* ****************************** */
|
||||
/*
|
||||
********************************
|
||||
* GfxDisplay
|
||||
********************************
|
||||
*/
|
||||
|
||||
GfxDisplay::GfxDisplay(GLFWwindow* a_window) {
|
||||
set_renderer(GfxPipeline::OpenGL);
|
||||
@@ -81,9 +85,11 @@ void GfxDisplay::render_graphics() {
|
||||
m_renderer->render_display(this);
|
||||
}
|
||||
|
||||
/* ****************************** */
|
||||
/* DISPLAY */
|
||||
/* ****************************** */
|
||||
/*
|
||||
********************************
|
||||
* DISPLAY
|
||||
********************************
|
||||
*/
|
||||
|
||||
namespace Display {
|
||||
|
||||
|
||||
+21
-4
@@ -6,11 +6,12 @@
|
||||
#include <functional>
|
||||
|
||||
#include "gfx.h"
|
||||
#include "display.h"
|
||||
#include "pipelines/opengl.h"
|
||||
|
||||
#include "common/log/log.h"
|
||||
#include "game/runtime.h"
|
||||
#include "display.h"
|
||||
|
||||
#include "pipelines/opengl.h"
|
||||
#include "game/system/newpad.h"
|
||||
|
||||
namespace {
|
||||
|
||||
@@ -29,7 +30,14 @@ void InitSettings(GfxSettings& settings) {
|
||||
// debug for now
|
||||
settings.debug = true;
|
||||
|
||||
return;
|
||||
// we're not setting controller info
|
||||
settings.pad_mapping_info.input_mode = false;
|
||||
// use buffered input mode
|
||||
settings.pad_mapping_info.buffer_mode = true;
|
||||
// debug input settings
|
||||
settings.pad_mapping_info.debug = true;
|
||||
// use a default mapping
|
||||
Pad::DefaultMapping(settings.pad_mapping_info);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
@@ -57,6 +65,8 @@ u32 Init() {
|
||||
lg::info("GFX Init");
|
||||
// initialize settings
|
||||
InitSettings(g_settings);
|
||||
// guarantee we have no keys detected by pad
|
||||
Pad::ForceClearKeys();
|
||||
|
||||
if (g_settings.renderer->init(g_settings)) {
|
||||
lg::error("Gfx::Init error");
|
||||
@@ -75,6 +85,9 @@ u32 Init() {
|
||||
void Loop(std::function<bool()> f) {
|
||||
lg::info("GFX Loop");
|
||||
while (f()) {
|
||||
// clean the inputs
|
||||
Pad::ClearKeys();
|
||||
|
||||
// check if we have a display
|
||||
if (Display::GetMainDisplay()) {
|
||||
// lg::debug("run display");
|
||||
@@ -116,4 +129,8 @@ void texture_relocate(u32 destination, u32 source, u32 format) {
|
||||
}
|
||||
}
|
||||
|
||||
int PadIsPressed(Pad::Button button, int port) {
|
||||
return Pad::IsPressed(g_settings.pad_mapping_info, button, port);
|
||||
}
|
||||
|
||||
} // namespace Gfx
|
||||
|
||||
+8
-1
@@ -7,8 +7,10 @@
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "game/kernel/kboot.h"
|
||||
#include "game/system/newpad.h"
|
||||
|
||||
// forward declarations
|
||||
struct GfxSettings;
|
||||
@@ -39,12 +41,15 @@ struct GfxRendererModule {
|
||||
struct GfxSettings {
|
||||
// current version of the settings. this should be set up so that newer versions are always higher
|
||||
// than older versions
|
||||
static constexpr u64 CURRENT_VERSION = 0x0000'0000'00001'0001;
|
||||
static constexpr u64 CURRENT_VERSION = 0x0000'0000'0002'0001;
|
||||
|
||||
u64 version; // the version of this settings struct
|
||||
const GfxRendererModule* renderer; // which rendering pipeline to use.
|
||||
int vsync; // (temp) number of screen update per frame
|
||||
bool debug; // graphics debugging
|
||||
|
||||
Pad::MappingInfo pad_mapping_info; // button mapping
|
||||
Pad::MappingInfo pad_mapping_info_backup; // button mapping backup (see newpad.h)
|
||||
};
|
||||
|
||||
namespace Gfx {
|
||||
@@ -64,4 +69,6 @@ void send_chain(const void* data, u32 offset);
|
||||
void texture_upload_now(const u8* tpage, int mode, u32 s7_ptr);
|
||||
void texture_relocate(u32 destination, u32 source, u32 format);
|
||||
|
||||
int PadIsPressed(Pad::Button button, int port);
|
||||
|
||||
} // namespace Gfx
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include "game/graphics/opengl_renderer/OpenGLRenderer.h"
|
||||
#include "game/graphics/texture/TexturePool.h"
|
||||
#include "game/graphics/dma/dma_copy.h"
|
||||
#include "game/system/newpad.h"
|
||||
#include "common/log/log.h"
|
||||
#include "common/goal_constants.h"
|
||||
#include "game/runtime.h"
|
||||
@@ -50,8 +51,10 @@ void SetDisplayCallbacks(GLFWwindow* d) {
|
||||
glfwSetKeyCallback(d, [](GLFWwindow* /*window*/, int key, int scancode, int action, int mods) {
|
||||
if (action == GlfwKeyAction::Press) {
|
||||
lg::debug("KEY PRESS: key: {} scancode: {} mods: {:X}", key, scancode, mods);
|
||||
Pad::OnKeyPress(key);
|
||||
} else if (action == GlfwKeyAction::Release) {
|
||||
lg::debug("KEY RELEASE: key: {} scancode: {} mods: {:X}", key, scancode, mods);
|
||||
Pad::OnKeyRelease(key);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
+113
-12
@@ -409,27 +409,128 @@ void CacheFlush(void* mem, int size) {
|
||||
* Prints an error if it fails to open.
|
||||
*/
|
||||
u64 CPadOpen(u64 cpad_info, s32 pad_number) {
|
||||
auto info = Ptr<CpadInfo>(cpad_info).c();
|
||||
if (info->cpad_file == 0) {
|
||||
auto cpad = Ptr<CPadInfo>(cpad_info).c();
|
||||
if (cpad->cpad_file == 0) {
|
||||
// not open, so we will open it
|
||||
info->cpad_file =
|
||||
cpad->cpad_file =
|
||||
ee::scePadPortOpen(pad_number, 0, pad_dma_buf + pad_number * SCE_PAD_DMA_BUFFER_SIZE);
|
||||
if (info->cpad_file < 1) {
|
||||
MsgErr("dkernel: !open cpad #%d (%d)\n", pad_number, info->cpad_file);
|
||||
if (cpad->cpad_file < 1) {
|
||||
MsgErr("dkernel: !open cpad #%d (%d)\n", pad_number, cpad->cpad_file);
|
||||
}
|
||||
info->new_pad = 1;
|
||||
info->state = 0;
|
||||
cpad->new_pad = 1;
|
||||
cpad->state = 0;
|
||||
}
|
||||
return cpad_info;
|
||||
}
|
||||
|
||||
// TODO CPadGetData
|
||||
void CPadGetData() {
|
||||
static bool warned = false;
|
||||
if (!warned) {
|
||||
lg::warn("ignoring calls to CPadGetData");
|
||||
warned = true;
|
||||
Ptr<CPadInfo> CPadGetData(u64 cpad_info) {
|
||||
auto cpad = Ptr<CPadInfo>(cpad_info).c();
|
||||
auto pad_state = scePadGetState(cpad->number, 0);
|
||||
if (pad_state == scePadStateDiscon) {
|
||||
cpad->state = 0;
|
||||
}
|
||||
cpad->valid = pad_state | 0x80;
|
||||
switch (cpad->state) {
|
||||
// case 99: // functional
|
||||
default: // controller is functioning as normal
|
||||
if (pad_state == scePadStateStable || pad_state == scePadStateFindCTP1) {
|
||||
scePadRead(cpad->number, 0, (u8*)cpad);
|
||||
// ps2 controllers would send an enabled bit if the button was NOT pressed, but we don't do
|
||||
// that here. removed code that flipped the bits.
|
||||
|
||||
if (cpad->change_time != 0) {
|
||||
scePadSetActDirect(cpad->number, 0, cpad->direct);
|
||||
}
|
||||
cpad->valid = pad_state;
|
||||
}
|
||||
break;
|
||||
case 0: // unavailable
|
||||
if (pad_state == scePadStateStable || pad_state == scePadStateFindCTP1) {
|
||||
auto pad_mode = scePadInfoMode(cpad->number, 0, InfoModeCurID, 0);
|
||||
if (pad_mode != 0) {
|
||||
auto vibration_mode = scePadInfoMode(cpad->number, 0, InfoModeCurExID, 0);
|
||||
if (vibration_mode > 0) {
|
||||
// vibration supported
|
||||
pad_mode = vibration_mode;
|
||||
}
|
||||
if (pad_mode == 4) {
|
||||
// controller mode
|
||||
cpad->state = 40;
|
||||
} else if (pad_mode == 7) {
|
||||
// dualshock mode
|
||||
cpad->state = 70;
|
||||
} else {
|
||||
// who knows mode
|
||||
cpad->state = 90;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 40: // controller mode - check for extra modes
|
||||
cpad->change_time = 0;
|
||||
if (scePadInfoMode(cpad->number, 0, InfoModeIdTable, -1) == 0) {
|
||||
// no controller modes
|
||||
cpad->state = 90;
|
||||
return make_ptr<CPadInfo>(cpad);
|
||||
}
|
||||
cpad->state = 41;
|
||||
case 41: // controller mode - change to dualshock mode!
|
||||
// try to enter the 2nd controller mode (dualshock for ds2's)
|
||||
if (scePadSetMainMode(cpad->number, 0, 1, 3) == 1) {
|
||||
cpad->state = 42;
|
||||
}
|
||||
break;
|
||||
case 42: // controller mode change check
|
||||
if (scePadGetReqState(cpad->number, 0) == scePadReqStateFailed) {
|
||||
// failed to change to DS2
|
||||
cpad->state = 41;
|
||||
}
|
||||
if (scePadGetReqState(cpad->number, 0) == scePadReqStateComplete) {
|
||||
// change successful. go back to the beginning.
|
||||
cpad->state = 0;
|
||||
}
|
||||
break;
|
||||
case 70: // dualshock mode - check vibration
|
||||
// get number of actuators (2 for DS2)
|
||||
if (scePadInfoAct(cpad->number, 0, -1, 0) < 1) {
|
||||
// no actuators means no vibration. skip to end!
|
||||
cpad->change_time = 0;
|
||||
cpad->state = 99;
|
||||
} else {
|
||||
// we have actuators to use.
|
||||
cpad->change_time = 1; // remember to update vibration.
|
||||
cpad->state = 75;
|
||||
}
|
||||
break;
|
||||
case 75: // set actuator vib param info
|
||||
if (scePadSetActAlign(cpad->number, 0, cpad->align) != 0) {
|
||||
if (scePadInfoPressMode(cpad->number, 0) == 1) {
|
||||
// pressure buttons supported
|
||||
cpad->state = 76;
|
||||
} else {
|
||||
// no pressure buttons, done with controller setup
|
||||
cpad->state = 99;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 76: // enter pressure mode
|
||||
if (scePadEnterPressMode(cpad->number, 0) == 1) {
|
||||
cpad->state = 78;
|
||||
}
|
||||
break;
|
||||
case 78: // pressure mode request check
|
||||
if (scePadGetReqState(cpad->number, 0) == 1) {
|
||||
cpad->state = 76;
|
||||
}
|
||||
if (scePadGetReqState(cpad->number, 0) == 0) {
|
||||
cpad->state = 99;
|
||||
}
|
||||
break;
|
||||
case 90:
|
||||
break; // unsupported controller. too bad!
|
||||
}
|
||||
return make_ptr<CPadInfo>(cpad);
|
||||
}
|
||||
|
||||
// TODO InstallHandler
|
||||
|
||||
+19
-7
@@ -89,21 +89,33 @@ void CacheFlush(void* mem, int size);
|
||||
void InitMachineScheme();
|
||||
|
||||
//! Mirror of cpad-info
|
||||
struct CpadInfo {
|
||||
struct CPadInfo {
|
||||
u8 valid;
|
||||
u8 status;
|
||||
s16 button0;
|
||||
u8 rx;
|
||||
u8 ry;
|
||||
u8 lx;
|
||||
u8 ly;
|
||||
u16 button0;
|
||||
u8 rightx;
|
||||
u8 righty;
|
||||
u8 leftx;
|
||||
u8 lefty;
|
||||
u8 abutton[12];
|
||||
u8 dummy[12];
|
||||
s32 number;
|
||||
s32 cpad_file;
|
||||
u8 _pad0[36];
|
||||
u32 button0_abs[3];
|
||||
u32 button0_shadow_abs[1];
|
||||
u32 button0_rel[3];
|
||||
float stick0_dir;
|
||||
float stick0_speed;
|
||||
s32 new_pad;
|
||||
s32 state;
|
||||
u8 align[6];
|
||||
u8 direct[6];
|
||||
u8 buzz_val[2];
|
||||
u8 __pad[2];
|
||||
u64 buzz_time[2];
|
||||
u32 buzz;
|
||||
s32 buzz_act;
|
||||
s32 change_time; // actually u64 in goal!
|
||||
};
|
||||
|
||||
struct FileStream {
|
||||
|
||||
@@ -5,9 +5,6 @@
|
||||
* Stub implementation of the EE CD/DVD library
|
||||
*/
|
||||
|
||||
#ifndef JAK1_LIBCDVD_EE_H
|
||||
#define JAK1_LIBCDVD_EE_H
|
||||
|
||||
// for sceCdInit
|
||||
#define SCECdINIT 0x00
|
||||
|
||||
@@ -34,5 +31,3 @@ int sceCdMmode(int media);
|
||||
int sceCdDiskReady(int mode);
|
||||
int sceCdGetDiskType();
|
||||
} // namespace ee
|
||||
|
||||
#endif // JAK1_LIBCDVD_EE_H
|
||||
|
||||
@@ -1,7 +1,16 @@
|
||||
#include "common/util/assert.h"
|
||||
#include "libpad.h"
|
||||
|
||||
#include "game/kernel/kmachine.h"
|
||||
#include "game/graphics/gfx.h"
|
||||
|
||||
/*!
|
||||
* @file libpad.h
|
||||
* Stub implementation of the EE pad (controller) library
|
||||
*/
|
||||
|
||||
namespace ee {
|
||||
|
||||
int scePadPortOpen(int port, int slot, void*) {
|
||||
// we are expected to return a non-zero file descriptor.
|
||||
// we return the port + 1 and succeed always.
|
||||
@@ -9,4 +18,114 @@ int scePadPortOpen(int port, int slot, void*) {
|
||||
assert(slot == 0);
|
||||
return port + 1;
|
||||
}
|
||||
|
||||
int scePadGetState(int port, int slot) {
|
||||
// pretend we always have a controller connected
|
||||
return scePadStateStable;
|
||||
}
|
||||
|
||||
// controller mode array for DS2s
|
||||
// the game will try very hard to force into dualshock mode so let's not even try
|
||||
static const int libpad_DualShock2_ModeIDs[2] = {
|
||||
(int)PadMode::Controller, // no vibration or pressure sensitive buttons
|
||||
(int)PadMode::DualShock2 // vibration + pressure sensitive buttons
|
||||
};
|
||||
int scePadInfoMode(int port, int slot, int term, int offs) {
|
||||
if (term == InfoModeCurExID) {
|
||||
// return vibration mode ID. that's just dualshock mode.
|
||||
return libpad_DualShock2_ModeIDs[1];
|
||||
|
||||
} else if (term == InfoModeCurID) {
|
||||
// return mode ID. just dualshock.
|
||||
return libpad_DualShock2_ModeIDs[1];
|
||||
|
||||
} else if (term == InfoModeCurExOffs) {
|
||||
// offset of current mode ID
|
||||
return 1;
|
||||
|
||||
} else if (term == InfoModeIdTable) {
|
||||
if (offs == -1)
|
||||
return 2;
|
||||
|
||||
return libpad_DualShock2_ModeIDs[offs]; // ?
|
||||
}
|
||||
|
||||
// invalid controller or some other error
|
||||
return 0;
|
||||
}
|
||||
|
||||
// order of pressure sensitive buttons in memory (not the same as their bit order...).
|
||||
static const Pad::Button libpad_PadPressureButtons[] = {
|
||||
Pad::Button::Right, Pad::Button::Left, Pad::Button::Up, Pad::Button::Down,
|
||||
Pad::Button::Triangle, Pad::Button::Circle, Pad::Button::X, Pad::Button::Square,
|
||||
Pad::Button::L1, Pad::Button::R1, Pad::Button::L2, Pad::Button::R2};
|
||||
// reads controller data and writes it to a buffer in rdata (must be at least 32 bytes large).
|
||||
// returns buffer size (32) or 0 on error.
|
||||
int scePadRead(int port, int slot, u8* rdata) {
|
||||
auto cpad = (CPadInfo*)(rdata);
|
||||
|
||||
cpad->valid = 0; // success
|
||||
cpad->status = 0x70 /* (dualshock2) */ | (20 / 2); /* (dualshock2 data size) */
|
||||
|
||||
cpad->rightx = 0;
|
||||
cpad->righty = 0;
|
||||
cpad->leftx = 0;
|
||||
cpad->lefty = 0;
|
||||
|
||||
// pressure sensitivity. ignore for now.
|
||||
for (int i = 0; i < 12; ++i) {
|
||||
cpad->abutton[i] = Gfx::PadIsPressed(libpad_PadPressureButtons[i], port) * 255;
|
||||
}
|
||||
|
||||
cpad->button0 = 0;
|
||||
for (int i = 0; i < 16; ++i) {
|
||||
cpad->button0 |= Gfx::PadIsPressed((Pad::Button)i, port) << i;
|
||||
}
|
||||
|
||||
return 32;
|
||||
}
|
||||
|
||||
// buzzer control. We don't care right now, return success.
|
||||
int scePadSetActDirect(int port, int slot, const u8* data) {
|
||||
return 1;
|
||||
}
|
||||
int scePadSetActAlign(int port, int slot, const u8* data) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
// we also don't care
|
||||
int scePadSetMainMode(int port, int slot, int offs, int lock) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
// async pad functions are gonna be synchronous so this always succeeds
|
||||
int scePadGetReqState(int port, int slot) {
|
||||
return scePadReqStateComplete;
|
||||
}
|
||||
|
||||
int scePadInfoAct(int port, int slot, int actno, int term) {
|
||||
if (actno == -1)
|
||||
return 2; // i think?
|
||||
if (actno < 2) {
|
||||
if (term == InfoActSub) {
|
||||
return 1; // whatever
|
||||
} else if (term == InfoActFunc) {
|
||||
return 1; // whatever
|
||||
} else if (term == InfoActSize) {
|
||||
return 0; // whatever
|
||||
} else if (term == InfoActCurr) {
|
||||
return 1; // whatever
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int scePadInfoPressMode(int port, int slot) {
|
||||
return 0; // we do NOT support pressure sensitive buttons right now
|
||||
}
|
||||
|
||||
int scePadEnterPressMode(int port, int slot) {
|
||||
return 1; // we dont support pressure button, but if we did this would work straight away
|
||||
}
|
||||
|
||||
} // namespace ee
|
||||
|
||||
+56
-1
@@ -1,7 +1,62 @@
|
||||
#pragma once
|
||||
|
||||
/*!
|
||||
* @file libpad.h
|
||||
* Stub implementation of the EE pad (controller) library
|
||||
*/
|
||||
|
||||
#include "common/common_types.h"
|
||||
|
||||
#define SCE_PAD_DMA_BUFFER_SIZE 0x100
|
||||
|
||||
// pad status
|
||||
#define scePadStateDiscon 0
|
||||
#define scePadStateFindPad 1
|
||||
#define scePadStateFindCTP1 2
|
||||
#define scePadStateExecCmd 5
|
||||
#define scePadStateStable 6
|
||||
#define scePadStateError 7
|
||||
#define scePadStateClosed 99
|
||||
|
||||
// pad mode info checks
|
||||
#define InfoModeCurID 1
|
||||
#define InfoModeCurExID 2
|
||||
#define InfoModeCurExOffs 3
|
||||
#define InfoModeIdTable 4
|
||||
|
||||
// pad async request states
|
||||
#define scePadReqStateComplete 0
|
||||
#define scePadReqStateFaild 1 // lol
|
||||
#define scePadReqStateFailed 1
|
||||
#define scePadReqStateBusy 2
|
||||
|
||||
// pad actuator info checks
|
||||
#define InfoActFunc 1
|
||||
#define InfoActSub 2
|
||||
#define InfoActSize 3
|
||||
#define InfoActCurr 4
|
||||
|
||||
namespace ee {
|
||||
|
||||
// controller modes (not in the lib)
|
||||
enum PadMode {
|
||||
Controller = 4,
|
||||
DualShock = 7,
|
||||
DualShock2 = DualShock,
|
||||
NeGcon = 2,
|
||||
Joystick = 5,
|
||||
NamcoGun = 6
|
||||
};
|
||||
|
||||
int scePadPortOpen(int port, int slot, void* data);
|
||||
}
|
||||
int scePadGetState(int port, int slot);
|
||||
int scePadInfoMode(int port, int slot, int term, int offs);
|
||||
int scePadRead(int port, int slot, u8* rdata);
|
||||
int scePadSetActDirect(int port, int slot, const u8* data);
|
||||
int scePadSetActAlign(int port, int slot, const u8* data);
|
||||
int scePadSetMainMode(int port, int slot, int offs, int lock);
|
||||
int scePadGetReqState(int port, int slot);
|
||||
int scePadInfoAct(int port, int slot, int actno, int term);
|
||||
int scePadInfoPressMode(int port, int slot);
|
||||
int scePadEnterPressMode(int port, int slot);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,114 @@
|
||||
/*!
|
||||
* @file newpad.cpp
|
||||
* PC-port specific cpad implementation on the C kernel. Monitors button inputs.
|
||||
* Actual input detection is done through window events and is gfx pipeline-dependent.
|
||||
*/
|
||||
|
||||
#include "newpad.h"
|
||||
#include "common/log/log.h"
|
||||
|
||||
#include "game/graphics/pipelines/opengl.h" // for GLFW macros
|
||||
|
||||
namespace Pad {
|
||||
|
||||
/*
|
||||
********************************
|
||||
* Key checking
|
||||
********************************
|
||||
*/
|
||||
|
||||
std::unordered_map<int, int> g_key_status;
|
||||
std::unordered_map<int, int> g_buffered_key_status;
|
||||
|
||||
void ForceClearKeys() {
|
||||
g_key_status.clear();
|
||||
g_buffered_key_status.clear();
|
||||
}
|
||||
|
||||
void ClearKeys() {
|
||||
for (auto& key : g_key_status) {
|
||||
key.second = false;
|
||||
}
|
||||
for (auto& key : g_buffered_key_status) {
|
||||
key.second = false;
|
||||
}
|
||||
}
|
||||
|
||||
void OnKeyPress(int key) {
|
||||
// set absolute key status
|
||||
if (g_key_status.find(key) == g_key_status.end()) {
|
||||
g_key_status.insert(std::make_pair(key, 1));
|
||||
} else {
|
||||
g_key_status.at(key) = 1;
|
||||
}
|
||||
|
||||
// set buffered key status
|
||||
if (g_buffered_key_status.find(key) == g_buffered_key_status.end()) {
|
||||
g_buffered_key_status.insert(std::make_pair(key, 1));
|
||||
} else {
|
||||
g_buffered_key_status.at(key) = 1;
|
||||
}
|
||||
}
|
||||
|
||||
void OnKeyRelease(int key) {
|
||||
// set absolute key status
|
||||
// no bounds checking for now in order to catch bugs
|
||||
g_key_status.at(key) = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
********************************
|
||||
* Pad checking
|
||||
********************************
|
||||
*/
|
||||
|
||||
static int CheckPadIdx(int pad) {
|
||||
if (pad < 0 || pad > CONTROLLER_COUNT) {
|
||||
lg::error("Invalid pad {}, returning pad 0", pad);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// returns 1 if button is pressed. returns 0 if invalid or not pressed.
|
||||
int IsPressed(MappingInfo& mapping, Button button, int pad = 0) {
|
||||
auto key = mapping.pad_mapping[CheckPadIdx(pad)][(int)button];
|
||||
if (key == -1)
|
||||
return 0;
|
||||
auto& keymap = mapping.buffer_mode ? g_buffered_key_status : g_key_status;
|
||||
if (keymap.find(key) == keymap.end())
|
||||
return 0;
|
||||
return keymap.at(key);
|
||||
}
|
||||
|
||||
// map a button on a pad to a key
|
||||
void MapButton(MappingInfo& mapping, Button button, int pad, int key) {
|
||||
// check if pad is valid. dont map buttons with invalid pads.
|
||||
if (CheckPadIdx(pad) != pad)
|
||||
return;
|
||||
|
||||
mapping.pad_mapping[pad][(int)button] = key;
|
||||
}
|
||||
|
||||
// reset button mappings
|
||||
void DefaultMapping(MappingInfo& mapping) {
|
||||
// make every button invalid
|
||||
for (int p = 0; p < CONTROLLER_COUNT; ++p) {
|
||||
for (int i = 0; i < (int)Button::Max; ++i) {
|
||||
MapButton(mapping, (Button)i, p, -1);
|
||||
}
|
||||
}
|
||||
|
||||
// face buttons
|
||||
MapButton(mapping, Button::Ecks, 0, GLFW_KEY_Z);
|
||||
MapButton(mapping, Button::Square, 0, GLFW_KEY_X);
|
||||
MapButton(mapping, Button::Triangle, 0, GLFW_KEY_S);
|
||||
MapButton(mapping, Button::Circle, 0, GLFW_KEY_A);
|
||||
|
||||
// dpad
|
||||
MapButton(mapping, Button::Up, 0, GLFW_KEY_UP);
|
||||
MapButton(mapping, Button::Right, 0, GLFW_KEY_RIGHT);
|
||||
MapButton(mapping, Button::Down, 0, GLFW_KEY_DOWN);
|
||||
MapButton(mapping, Button::Left, 0, GLFW_KEY_LEFT);
|
||||
}
|
||||
|
||||
}; // namespace Pad
|
||||
@@ -0,0 +1,74 @@
|
||||
#pragma once
|
||||
|
||||
/*!
|
||||
* @file newpad.h
|
||||
* PC-port specific cpad implementation on the C kernel. Monitors button inputs.
|
||||
* Actual input detection is done through window events and is gfx pipeline-dependent.
|
||||
*/
|
||||
|
||||
/* NOTE ABOUT KEY VALUES!
|
||||
* I am using the renderer-dependent key value macros here (at least for now). This means that the
|
||||
* button mapping may be renderer-dependent. When changing renderers, make sure to backup the
|
||||
* original button mapping or something so that the user can reset it afterwards. Eventually we
|
||||
* should fix this (or maybe it's not even a problem).
|
||||
*/
|
||||
|
||||
#include <unordered_map>
|
||||
|
||||
namespace Pad {
|
||||
|
||||
static constexpr int CONTROLLER_COUNT = 2; // support 2 controllers.
|
||||
|
||||
// mirrors goal enum pad-buttons. used as indices to an array!
|
||||
enum class Button {
|
||||
Select = 0,
|
||||
L3 = 1,
|
||||
R3 = 2,
|
||||
Start = 3,
|
||||
|
||||
Up = 4,
|
||||
Right = 5,
|
||||
Down = 6,
|
||||
Left = 7,
|
||||
|
||||
L2 = 8,
|
||||
R2 = 9,
|
||||
L1 = 10,
|
||||
R1 = 11,
|
||||
|
||||
Triangle = 12,
|
||||
Circle = 13,
|
||||
X = 14,
|
||||
Square = 15,
|
||||
|
||||
Max = 16,
|
||||
|
||||
// aliases
|
||||
Ecks = X,
|
||||
Cross = X,
|
||||
O = Circle
|
||||
};
|
||||
|
||||
struct MappingInfo {
|
||||
bool debug = true; // debug mode
|
||||
bool input_mode = false; // input mode for controller mapping
|
||||
bool buffer_mode = true; // use buffered inputs
|
||||
int pad_mapping[CONTROLLER_COUNT][(int)Pad::Button::Max]; // controller button mapping
|
||||
// TODO complex button mapping & key macros (e.g. shift+x for l2+r2 press etc.)
|
||||
};
|
||||
|
||||
// key-down status of any detected key.
|
||||
extern std::unordered_map<int, int> g_key_status;
|
||||
// key-down status of any detected key. this is buffered for the remainder of a frame.
|
||||
extern std::unordered_map<int, int> g_buffered_key_status;
|
||||
|
||||
void OnKeyPress(int key);
|
||||
void OnKeyRelease(int key);
|
||||
void ForceClearKeys();
|
||||
void ClearKeys();
|
||||
|
||||
void DefaultMapping(MappingInfo& mapping);
|
||||
int IsPressed(MappingInfo& mapping, Button button, int pad);
|
||||
void MapButton(MappingInfo& mapping, Button button, int pad, int key);
|
||||
|
||||
} // namespace Pad
|
||||
@@ -214,7 +214,6 @@
|
||||
(defmethod link-art! art-group ((obj art-group))
|
||||
"Links the elements of this art-group."
|
||||
|
||||
;; this check seems superfluous
|
||||
(when obj
|
||||
(countdown (s5-0 (-> obj length))
|
||||
(let* ((art-elt (-> obj data s5-0))
|
||||
|
||||
+33
-12
@@ -30,7 +30,15 @@
|
||||
(x 14)
|
||||
(square 15)
|
||||
)
|
||||
|
||||
|
||||
(defenum pad-type
|
||||
(normal 4)
|
||||
(analog 5)
|
||||
(dualshock 7)
|
||||
(negcon 2)
|
||||
(namco-gun 6)
|
||||
)
|
||||
|
||||
;; these forward declarations should probably go somewhere else...
|
||||
(define-extern get-current-time (function uint))
|
||||
(define-extern get-integral-current-time (function uint))
|
||||
@@ -38,16 +46,25 @@
|
||||
;; this gets set to #f later on.
|
||||
(define *cheat-mode* #t)
|
||||
|
||||
;; data that comes directly from hardware.
|
||||
;; data that comes directly from hardware. it's 32 bytes + type tag (ignored in C kernel).
|
||||
(deftype hw-cpad (basic)
|
||||
((valid uint8 :offset-assert 4)
|
||||
(status uint8 :offset-assert 5)
|
||||
(button0 uint16 :offset-assert 6)
|
||||
(rightx uint8 :offset-assert 8)
|
||||
(righty uint8 :offset-assert 9)
|
||||
(leftx uint8 :offset-assert 10)
|
||||
(lefty uint8 :offset-assert 11)
|
||||
(abutton uint8 12 :offset-assert 12)
|
||||
(;; BASIC CONTROLLER data
|
||||
;; status = 0x40 | (data length / 2)
|
||||
(valid uint8 :offset-assert 4) ;; 0 if success, 255 if fail
|
||||
(status uint8 :offset-assert 5) ;; depends on controller
|
||||
(button0 uint16 :offset-assert 6) ;; binary button states!
|
||||
;; DUALSHOCK or JOYSTICK data
|
||||
;; status (dualshock) = 0x70 | (data length / 2)
|
||||
;; status (joystick) = 0x50 | (data length / 2)
|
||||
(rightx uint8 :offset-assert 8) ;; right stick xdir
|
||||
(righty uint8 :offset-assert 9) ;; right stick ydir
|
||||
(leftx uint8 :offset-assert 10) ;; left stick xdir
|
||||
(lefty uint8 :offset-assert 11) ;; left stick ydir
|
||||
;; DUALSHOCK 2 data
|
||||
;; status = 0x70 | (data length / 2)
|
||||
(abutton uint8 12 :offset-assert 12) ;; pressure sensitivity information
|
||||
|
||||
;; pad buffer needs to be 32 bytes large.
|
||||
(dummy uint8 12 :offset-assert 24)
|
||||
)
|
||||
:method-count-assert 9
|
||||
@@ -57,7 +74,7 @@
|
||||
|
||||
;; data from hardware + additional info calculated here.
|
||||
(deftype cpad-info (hw-cpad)
|
||||
((number int32 :offset-assert 36)
|
||||
((number int32 :offset-assert 36) ;; controller port number
|
||||
(cpad-file int32 :offset-assert 40)
|
||||
(button0-abs pad-buttons 3 :offset-assert 44) ;; bitmask of buttons, pressed or not, with history
|
||||
(button0-shadow-abs pad-buttons 1 :offset-assert 56) ;; modify this to change button history in the future.
|
||||
@@ -66,7 +83,7 @@
|
||||
(stick0-speed float :offset-assert 76)
|
||||
(new-pad int32 :offset-assert 80)
|
||||
(state int32 :offset-assert 84)
|
||||
(align uint8 6 :offset-assert 88)
|
||||
(align uint8 6 :offset-assert 88) ;; hardware control of buzzing.
|
||||
(direct uint8 6 :offset-assert 94) ;; hardware control of buzzing.
|
||||
(buzz-val uint8 2 :offset-assert 100) ;; intensity for buzzing
|
||||
(buzz-time uint64 2 :offset-assert 104) ;; when to stop buzzing
|
||||
@@ -82,6 +99,10 @@
|
||||
:flag-assert #x900000088
|
||||
)
|
||||
|
||||
(defmacro cpad-type? (type)
|
||||
`(= (shr (-> pad status) 4) (cpad-type ,type))
|
||||
)
|
||||
|
||||
(defun cpad-invalid! ((pad cpad-info))
|
||||
"Reset all data in a cpad-info"
|
||||
(logior! (-> pad valid) 128)
|
||||
|
||||
Reference in New Issue
Block a user