feat: add support for keyboard and mouse input

This commit is contained in:
daoge_cmd
2026-03-01 18:50:55 +08:00
parent 9af787692e
commit bdef1f9412
12 changed files with 640 additions and 27 deletions

View File

@@ -919,6 +919,29 @@ void UIController::handleKeyPress(unsigned int iPad, unsigned int key)
pressed = InputManager.ButtonPressed(iPad,key); // Toggle
released = InputManager.ButtonReleased(iPad,key); // Toggle
#ifdef _WINDOWS64
// Keyboard menu input for player 0
if (iPad == 0)
{
bool kbDown = false, kbPressed = false, kbReleased = false;
switch(key)
{
case ACTION_MENU_UP: kbDown = KMInput.IsKeyDown(VK_UP); kbPressed = KMInput.IsKeyPressed(VK_UP); kbReleased = KMInput.IsKeyReleased(VK_UP); break;
case ACTION_MENU_DOWN: kbDown = KMInput.IsKeyDown(VK_DOWN); kbPressed = KMInput.IsKeyPressed(VK_DOWN); kbReleased = KMInput.IsKeyReleased(VK_DOWN); break;
case ACTION_MENU_LEFT: kbDown = KMInput.IsKeyDown(VK_LEFT); kbPressed = KMInput.IsKeyPressed(VK_LEFT); kbReleased = KMInput.IsKeyReleased(VK_LEFT); break;
case ACTION_MENU_RIGHT: kbDown = KMInput.IsKeyDown(VK_RIGHT); kbPressed = KMInput.IsKeyPressed(VK_RIGHT); kbReleased = KMInput.IsKeyReleased(VK_RIGHT); break;
case ACTION_MENU_OK: kbDown = KMInput.IsKeyDown(VK_RETURN); kbPressed = KMInput.IsKeyPressed(VK_RETURN); kbReleased = KMInput.IsKeyReleased(VK_RETURN); break;
case ACTION_MENU_A: kbDown = KMInput.IsKeyDown(VK_RETURN); kbPressed = KMInput.IsKeyPressed(VK_RETURN); kbReleased = KMInput.IsKeyReleased(VK_RETURN); break;
case ACTION_MENU_CANCEL: kbDown = KMInput.IsKeyDown(VK_ESCAPE); kbPressed = KMInput.IsKeyPressed(VK_ESCAPE); kbReleased = KMInput.IsKeyReleased(VK_ESCAPE); break;
case ACTION_MENU_B: kbDown = KMInput.IsKeyDown(VK_ESCAPE); kbPressed = KMInput.IsKeyPressed(VK_ESCAPE); kbReleased = KMInput.IsKeyReleased(VK_ESCAPE); break;
case ACTION_MENU_PAUSEMENU: kbDown = KMInput.IsKeyDown(VK_ESCAPE); kbPressed = KMInput.IsKeyPressed(VK_ESCAPE); kbReleased = KMInput.IsKeyReleased(VK_ESCAPE); break;
}
pressed = pressed || kbPressed;
released = released || kbReleased;
down = down || kbDown;
}
#endif
if(pressed) app.DebugPrintf("Pressed %d\n",key);
if(released) app.DebugPrintf("Released %d\n",key);
// Repeat handling

View File

@@ -18,6 +18,7 @@ Input::Input()
lReset = false;
rReset = false;
m_gamepadSneaking = false;
}
void Input::tick(LocalPlayer *player)
@@ -34,12 +35,30 @@ void Input::tick(LocalPlayer *player)
xa = -InputManager.GetJoypadStick_LX(iPad);
else
xa = 0.0f;
if( pMinecraft->localgameModes[iPad]->isInputAllowed(MINECRAFT_ACTION_FORWARD) || pMinecraft->localgameModes[iPad]->isInputAllowed(MINECRAFT_ACTION_BACKWARD) )
ya = InputManager.GetJoypadStick_LY(iPad);
else
ya = 0.0f;
#ifdef _WINDOWS64
// WASD movement (combine with gamepad)
if (iPad == 0)
{
float kbX = 0.0f, kbY = 0.0f;
if (KMInput.IsKeyDown('W')) kbY += 1.0f;
if (KMInput.IsKeyDown('S')) kbY -= 1.0f;
if (KMInput.IsKeyDown('A')) kbX += 1.0f; // inverted like gamepad
if (KMInput.IsKeyDown('D')) kbX -= 1.0f;
// Normalize diagonal
if (kbX != 0.0f && kbY != 0.0f) { kbX *= 0.707f; kbY *= 0.707f; }
if (pMinecraft->localgameModes[iPad]->isInputAllowed(MINECRAFT_ACTION_LEFT) || pMinecraft->localgameModes[iPad]->isInputAllowed(MINECRAFT_ACTION_RIGHT))
xa = max(min(xa + kbX, 1.0f), -1.0f);
if (pMinecraft->localgameModes[iPad]->isInputAllowed(MINECRAFT_ACTION_FORWARD) || pMinecraft->localgameModes[iPad]->isInputAllowed(MINECRAFT_ACTION_BACKWARD))
ya = max(min(ya + kbY, 1.0f), -1.0f);
}
#endif
#ifndef _CONTENT_PACKAGE
if (app.GetFreezePlayers())
{
@@ -47,7 +66,7 @@ void Input::tick(LocalPlayer *player)
player->abilities.flying = true;
}
#endif
if (!lReset)
{
if (xa*xa+ya*ya==0.0f)
@@ -62,9 +81,16 @@ void Input::tick(LocalPlayer *player)
{
if((player->ullButtonsPressed&(1LL<<MINECRAFT_ACTION_SNEAK_TOGGLE)) && pMinecraft->localgameModes[iPad]->isInputAllowed(MINECRAFT_ACTION_SNEAK_TOGGLE))
{
sneaking=!sneaking;
m_gamepadSneaking=!m_gamepadSneaking;
}
}
sneaking = m_gamepadSneaking;
#ifdef _WINDOWS64
// Keyboard hold-to-sneak (overrides gamepad toggle)
if (iPad == 0 && KMInput.IsKeyDown(VK_SHIFT) && !player->abilities.flying)
sneaking = true;
#endif
if(sneaking)
{
@@ -80,7 +106,7 @@ void Input::tick(LocalPlayer *player)
tx = InputManager.GetJoypadStick_RX(iPad)*(((float)app.GetGameSettings(iPad,eGameSetting_Sensitivity_InGame))/100.0f); // apply sensitivity to look
if( pMinecraft->localgameModes[iPad]->isInputAllowed(MINECRAFT_ACTION_LOOK_UP) || pMinecraft->localgameModes[iPad]->isInputAllowed(MINECRAFT_ACTION_LOOK_DOWN) )
ty = InputManager.GetJoypadStick_RY(iPad)*(((float)app.GetGameSettings(iPad,eGameSetting_Sensitivity_InGame))/100.0f); // apply sensitivity to look
#ifndef _CONTENT_PACKAGE
if (app.GetFreezePlayers()) tx = ty = 0.0f;
#endif
@@ -100,16 +126,35 @@ void Input::tick(LocalPlayer *player)
tx = ty = 0.0f;
}
player->interpolateTurn(tx * abs(tx) * turnSpeed, ty * abs(ty) * turnSpeed);
#ifdef _WINDOWS64
// Mouse look (added after stick-based turn)
if (iPad == 0 && KMInput.IsCaptured())
{
float mouseSensitivity = 1.25f;
float mdx = KMInput.GetMouseDeltaX() * mouseSensitivity;
float mdy = -KMInput.GetMouseDeltaY() * mouseSensitivity;
if (app.GetGameSettings(iPad, eGameSetting_ControlInvertLook))
mdy = -mdy;
player->interpolateTurn(mdx, mdy);
}
#endif
//jumping = controller.isButtonPressed(0);
unsigned int jump = InputManager.GetValue(iPad, MINECRAFT_ACTION_JUMP);
if( jump > 0 && pMinecraft->localgameModes[iPad]->isInputAllowed(MINECRAFT_ACTION_JUMP) )
jumping = true;
else
jumping = false;
#ifdef _WINDOWS64
// Keyboard jump (Space)
if (iPad == 0 && KMInput.IsKeyDown(VK_SPACE) && pMinecraft->localgameModes[iPad]->isInputAllowed(MINECRAFT_ACTION_JUMP))
jumping = true;
#endif
#ifndef _CONTENT_PACKAGE
if (app.GetFreezePlayers()) jumping = false;
#endif

View File

@@ -16,7 +16,8 @@ public:
virtual void tick(LocalPlayer *player);
private:
bool lReset;
bool rReset;
bool m_gamepadSneaking;
};

View File

@@ -302,6 +302,15 @@ void LocalPlayer::aiStep()
// world with low food, then reload it in creative.
if(abilities.mayfly || isAllowedToFly() ) enoughFoodToSprint = true;
#ifdef _WINDOWS64
// Keyboard sprint: Ctrl held while moving forward
if (GetXboxPad() == 0 && KMInput.IsKeyDown(VK_CONTROL) && input->ya > 0.0f &&
enoughFoodToSprint && !isUsingItem() && !hasEffect(MobEffect::blindness) && onGround)
{
if (!isSprinting()) setSprinting(true);
}
#endif
// 4J - altered this slightly to make sure that the joypad returns to below returnTreshold in between registering two movements up to runThreshold
if (onGround && !isSprinting() && enoughFoodToSprint && !isUsingItem() && !hasEffect(MobEffect::blindness))
{

View File

@@ -16292,6 +16292,51 @@ xcopy /q /y /i /s /e $(ProjectDir)Durango\CU $(LayoutDir)Image\Loose\CU</Comman
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|ORBIS'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ContentPackage_Vita|ORBIS'">true</ExcludedFromBuild>
</ClInclude>
<ClInclude Include="Windows64\KeyboardMouseInput.h">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ContentPackage|Durango'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='CONTENTPACKAGE_SYMBOLS|Durango'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ReleaseForArt|Durango'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ContentPackage_NO_TU|Durango'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='DebugContentPackage|Durango'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Durango'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ContentPackage_Vita|Durango'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Durango'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ContentPackage|Xbox 360'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='CONTENTPACKAGE_SYMBOLS|Xbox 360'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ReleaseForArt|Xbox 360'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ContentPackage_NO_TU|Xbox 360'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Xbox 360'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ContentPackage_Vita|Xbox 360'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Xbox 360'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ContentPackage|x64'">false</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='CONTENTPACKAGE_SYMBOLS|x64'">false</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ReleaseForArt|x64'">false</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ContentPackage_NO_TU|x64'">false</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">false</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ContentPackage_Vita|x64'">false</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">false</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ContentPackage|PS3'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ContentPackage|PSVita'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='CONTENTPACKAGE_SYMBOLS|PS3'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='CONTENTPACKAGE_SYMBOLS|PSVita'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ReleaseForArt|PS3'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ReleaseForArt|PSVita'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ContentPackage_NO_TU|PS3'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ContentPackage_NO_TU|PSVita'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|PS3'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ContentPackage_Vita|PS3'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|PSVita'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ContentPackage_Vita|PSVita'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|PS3'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|PSVita'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ContentPackage|ORBIS'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='CONTENTPACKAGE_SYMBOLS|ORBIS'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ReleaseForArt|ORBIS'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ContentPackage_NO_TU|ORBIS'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|ORBIS'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|ORBIS'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ContentPackage_Vita|ORBIS'">true</ExcludedFromBuild>
</ClInclude>
<ClInclude Include="Windows64\Sentient\DynamicConfigurations.h">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ContentPackage|Durango'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='CONTENTPACKAGE_SYMBOLS|Durango'">true</ExcludedFromBuild>
@@ -29101,6 +29146,51 @@ xcopy /q /y /i /s /e $(ProjectDir)Durango\CU $(LayoutDir)Image\Loose\CU</Comman
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|ORBIS'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ContentPackage_Vita|ORBIS'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="Windows64\KeyboardMouseInput.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ContentPackage|Durango'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='CONTENTPACKAGE_SYMBOLS|Durango'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ReleaseForArt|Durango'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ContentPackage_NO_TU|Durango'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='DebugContentPackage|Durango'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Durango'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ContentPackage_Vita|Durango'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Durango'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ContentPackage|Xbox 360'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='CONTENTPACKAGE_SYMBOLS|Xbox 360'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ReleaseForArt|Xbox 360'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ContentPackage_NO_TU|Xbox 360'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Xbox 360'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ContentPackage_Vita|Xbox 360'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Xbox 360'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ContentPackage|x64'">false</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='CONTENTPACKAGE_SYMBOLS|x64'">false</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ReleaseForArt|x64'">false</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ContentPackage_NO_TU|x64'">false</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">false</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ContentPackage_Vita|x64'">false</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">false</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ContentPackage|PS3'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ContentPackage|PSVita'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='CONTENTPACKAGE_SYMBOLS|PS3'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='CONTENTPACKAGE_SYMBOLS|PSVita'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ReleaseForArt|PS3'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ReleaseForArt|PSVita'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ContentPackage_NO_TU|PS3'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ContentPackage_NO_TU|PSVita'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|PS3'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ContentPackage_Vita|PS3'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|PSVita'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ContentPackage_Vita|PSVita'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|PS3'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|PSVita'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ContentPackage|ORBIS'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='CONTENTPACKAGE_SYMBOLS|ORBIS'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ReleaseForArt|ORBIS'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ContentPackage_NO_TU|ORBIS'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|ORBIS'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|ORBIS'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ContentPackage_Vita|ORBIS'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="Windows64\Windows64_UIController.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='ContentPackage|Durango'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='CONTENTPACKAGE_SYMBOLS|Durango'">true</ExcludedFromBuild>

View File

@@ -2341,6 +2341,9 @@
<ClInclude Include="Windows64\Resource.h">
<Filter>Windows64</Filter>
</ClInclude>
<ClInclude Include="Windows64\KeyboardMouseInput.h">
<Filter>Windows64\Source Files</Filter>
</ClInclude>
<ClInclude Include="Windows64\Windows64_App.h">
<Filter>Windows64</Filter>
</ClInclude>
@@ -4770,6 +4773,9 @@
<ClCompile Include="Windows64\Windows64_Minecraft.cpp">
<Filter>Windows64\Source Files</Filter>
</ClCompile>
<ClCompile Include="Windows64\KeyboardMouseInput.cpp">
<Filter>Windows64\Source Files</Filter>
</ClCompile>
<ClCompile Include="Windows64\Windows64_App.cpp">
<Filter>Windows64</Filter>
</ClCompile>

View File

@@ -1452,6 +1452,21 @@ void Minecraft::run_middle()
if(InputManager.ButtonPressed(i, MINECRAFT_ACTION_RENDER_THIRD_PERSON)) localplayers[i]->ullButtonsPressed|=1LL<<MINECRAFT_ACTION_RENDER_THIRD_PERSON;
if(InputManager.ButtonPressed(i, MINECRAFT_ACTION_GAME_INFO)) localplayers[i]->ullButtonsPressed|=1LL<<MINECRAFT_ACTION_GAME_INFO;
#ifdef _WINDOWS64
// Keyboard/mouse button presses for player 0
if (i == 0)
{
if (KMInput.IsKeyPressed(VK_ESCAPE)) localplayers[i]->ullButtonsPressed |= 1LL<<MINECRAFT_ACTION_PAUSEMENU;
if (KMInput.IsKeyPressed('E')) localplayers[i]->ullButtonsPressed |= 1LL<<MINECRAFT_ACTION_INVENTORY;
if (KMInput.IsKeyPressed('Q')) localplayers[i]->ullButtonsPressed |= 1LL<<MINECRAFT_ACTION_DROP;
if (KMInput.IsKeyPressed('C')) localplayers[i]->ullButtonsPressed |= 1LL<<MINECRAFT_ACTION_CRAFTING;
if (KMInput.IsKeyPressed(VK_F5)) localplayers[i]->ullButtonsPressed |= 1LL<<MINECRAFT_ACTION_RENDER_THIRD_PERSON;
// In flying mode, Shift held = sneak/descend
if (localplayers[i]->abilities.flying && KMInput.IsKeyDown(VK_SHIFT))
localplayers[i]->ullButtonsPressed |= 1LL<<MINECRAFT_ACTION_SNEAK_TOGGLE;
}
#endif
#ifndef _FINAL_BUILD
if( app.DebugSettingsOn() && app.GetUseDPadForDebug() )
{
@@ -3177,6 +3192,30 @@ void Minecraft::tick(bool bFirst, bool bUpdateTextures)
{
wheel = -1;
}
#ifdef _WINDOWS64
// Mouse scroll wheel for hotbar
if (iPad == 0)
{
int kbWheel = KMInput.GetScrollDelta();
if (kbWheel > 0 && gameMode->isInputAllowed(MINECRAFT_ACTION_LEFT_SCROLL)) wheel += 1;
else if (kbWheel < 0 && gameMode->isInputAllowed(MINECRAFT_ACTION_RIGHT_SCROLL)) wheel -= 1;
// 1-9 keys for direct hotbar selection
if (gameMode->isInputAllowed(MINECRAFT_ACTION_LEFT_SCROLL))
{
for (int k = '1'; k <= '9'; k++)
{
if (KMInput.IsKeyPressed(k))
{
player->inventory->selected = k - '1';
app.SetOpacityTimer(iPad);
break;
}
}
}
}
#endif
if (wheel != 0)
{
player->inventory->swapPaint(wheel);
@@ -3208,6 +3247,13 @@ void Minecraft::tick(bool bFirst, bool bUpdateTextures)
player->handleMouseClick(0);
player->lastClickTick[0] = ticks;
}
#ifdef _WINDOWS64
else if (iPad == 0 && KMInput.IsCaptured() && KMInput.IsMousePressed(0))
{
player->handleMouseClick(0);
player->lastClickTick[0] = ticks;
}
#endif
if (InputManager.ButtonDown(iPad, MINECRAFT_ACTION_ACTION) && ticks - player->lastClickTick[0] >= timer->ticksPerSecond / 4)
{
@@ -3215,8 +3261,19 @@ void Minecraft::tick(bool bFirst, bool bUpdateTextures)
player->handleMouseClick(0);
player->lastClickTick[0] = ticks;
}
#ifdef _WINDOWS64
else if (iPad == 0 && KMInput.IsCaptured() && KMInput.IsMouseDown(0) && ticks - player->lastClickTick[0] >= timer->ticksPerSecond / 4)
{
player->handleMouseClick(0);
player->lastClickTick[0] = ticks;
}
#endif
if(InputManager.ButtonDown(iPad, MINECRAFT_ACTION_ACTION) )
if(InputManager.ButtonDown(iPad, MINECRAFT_ACTION_ACTION)
#ifdef _WINDOWS64
|| (iPad == 0 && KMInput.IsCaptured() && KMInput.IsMouseDown(0))
#endif
)
{
player->handleMouseDown(0, true );
}
@@ -3237,14 +3294,23 @@ void Minecraft::tick(bool bFirst, bool bUpdateTextures)
*/
if( player->isUsingItem() )
{
if(!InputManager.ButtonDown(iPad, MINECRAFT_ACTION_USE)) gameMode->releaseUsingItem(player);
if(!InputManager.ButtonDown(iPad, MINECRAFT_ACTION_USE)
#ifdef _WINDOWS64
&& !(iPad == 0 && KMInput.IsCaptured() && KMInput.IsMouseDown(1))
#endif
) gameMode->releaseUsingItem(player);
}
else if( gameMode->isInputAllowed(MINECRAFT_ACTION_USE) )
{
#ifdef _WINDOWS64
bool useButtonDown = InputManager.ButtonDown(iPad, MINECRAFT_ACTION_USE) || (iPad == 0 && KMInput.IsCaptured() && KMInput.IsMouseDown(1));
#else
bool useButtonDown = InputManager.ButtonDown(iPad, MINECRAFT_ACTION_USE);
#endif
if( player->abilities.instabuild )
{
// 4J - attempt to handle click in special creative mode fashion if possible (used for placing blocks at regular intervals)
bool didClick = player->creativeModeHandleMouseClick(1, InputManager.ButtonDown(iPad, MINECRAFT_ACTION_USE) );
bool didClick = player->creativeModeHandleMouseClick(1, useButtonDown );
// If this handler has put us in lastClick_oldRepeat mode then it is because we aren't placing blocks - behave largely as the code used to
if( player->lastClickState == LocalPlayer::lastClick_oldRepeat )
{
@@ -3256,7 +3322,7 @@ void Minecraft::tick(bool bFirst, bool bUpdateTextures)
else
{
// Otherwise just the original game code for handling autorepeat
if (InputManager.ButtonDown(iPad, MINECRAFT_ACTION_USE) && ticks - player->lastClickTick[1] >= timer->ticksPerSecond / 4)
if (useButtonDown && ticks - player->lastClickTick[1] >= timer->ticksPerSecond / 4)
{
player->handleMouseClick(1);
player->lastClickTick[1] = ticks;
@@ -3272,7 +3338,7 @@ void Minecraft::tick(bool bFirst, bool bUpdateTextures)
bool firstClick = ( player->lastClickTick[1] == 0 );
bool autoRepeat = ticks - player->lastClickTick[1] >= timer->ticksPerSecond / 4;
if ( player->isRiding() || player->isSprinting() || player->isSleeping() ) autoRepeat = false;
if (InputManager.ButtonDown(iPad, MINECRAFT_ACTION_USE) )
if (useButtonDown )
{
// If the player has just exited a bed, then delay the time before a repeat key is allowed without releasing
if(player->isSleeping() ) player->lastClickTick[1] = ticks + (timer->ticksPerSecond * 2);

View File

@@ -0,0 +1,217 @@
#include "stdafx.h"
#ifdef _WINDOWS64
#include "KeyboardMouseInput.h"
KeyboardMouseInput KMInput;
KeyboardMouseInput::KeyboardMouseInput()
: m_mouseDeltaX(0.0f)
, m_mouseDeltaY(0.0f)
, m_mouseDeltaXAccum(0.0f)
, m_mouseDeltaYAccum(0.0f)
, m_scrollDelta(0)
, m_scrollDeltaAccum(0)
, m_captured(false)
, m_hWnd(NULL)
, m_initialized(false)
{
memset(m_keyState, 0, sizeof(m_keyState));
memset(m_keyStatePrev, 0, sizeof(m_keyStatePrev));
memset(m_mouseButtons, 0, sizeof(m_mouseButtons));
memset(m_mouseButtonsPrev, 0, sizeof(m_mouseButtonsPrev));
}
KeyboardMouseInput::~KeyboardMouseInput()
{
if (m_captured)
{
SetCapture(false);
}
}
void KeyboardMouseInput::Init(HWND hWnd)
{
m_hWnd = hWnd;
m_initialized = true;
// Register for raw mouse input
RAWINPUTDEVICE rid;
rid.usUsagePage = HID_USAGE_PAGE_GENERIC;
rid.usUsage = HID_USAGE_GENERIC_MOUSE;
rid.dwFlags = 0;
rid.hwndTarget = hWnd;
RegisterRawInputDevices(&rid, 1, sizeof(rid));
}
void KeyboardMouseInput::Tick()
{
// Snapshot accumulated mouse deltas
m_mouseDeltaX = m_mouseDeltaXAccum;
m_mouseDeltaY = m_mouseDeltaYAccum;
m_mouseDeltaXAccum = 0.0f;
m_mouseDeltaYAccum = 0.0f;
// Snapshot scroll delta
m_scrollDelta = m_scrollDeltaAccum;
m_scrollDeltaAccum = 0;
// Keep cursor pinned to center while captured
if (m_captured)
CenterCursor();
}
void KeyboardMouseInput::EndFrame()
{
// Advance previous state for next frame's edge detection.
// Must be called AFTER all consumers have read IsKeyPressed/Released etc.
memcpy(m_keyStatePrev, m_keyState, sizeof(m_keyState));
memcpy(m_mouseButtonsPrev, m_mouseButtons, sizeof(m_mouseButtons));
}
void KeyboardMouseInput::OnKeyDown(WPARAM vk)
{
if (vk < 256)
{
m_keyState[vk] = true;
}
}
void KeyboardMouseInput::OnKeyUp(WPARAM vk)
{
if (vk < 256)
{
m_keyState[vk] = false;
}
}
void KeyboardMouseInput::OnRawMouseInput(LPARAM lParam)
{
if (!m_captured) return;
UINT dwSize = 0;
GetRawInputData((HRAWINPUT)lParam, RID_INPUT, NULL, &dwSize, sizeof(RAWINPUTHEADER));
BYTE* lpb = (BYTE*)alloca(dwSize);
if (GetRawInputData((HRAWINPUT)lParam, RID_INPUT, lpb, &dwSize, sizeof(RAWINPUTHEADER)) != dwSize)
return;
RAWINPUT* raw = (RAWINPUT*)lpb;
if (raw->header.dwType == RIM_TYPEMOUSE)
{
if (raw->data.mouse.usFlags == MOUSE_MOVE_RELATIVE)
{
m_mouseDeltaXAccum += (float)raw->data.mouse.lLastX;
m_mouseDeltaYAccum += (float)raw->data.mouse.lLastY;
}
}
}
void KeyboardMouseInput::OnMouseButton(int button, bool down)
{
if (button >= 0 && button < 3)
{
m_mouseButtons[button] = down;
}
}
void KeyboardMouseInput::OnMouseWheel(int delta)
{
m_scrollDeltaAccum += delta;
}
void KeyboardMouseInput::ClearAllState()
{
memset(m_keyState, 0, sizeof(m_keyState));
memset(m_mouseButtons, 0, sizeof(m_mouseButtons));
m_mouseDeltaXAccum = 0.0f;
m_mouseDeltaYAccum = 0.0f;
m_scrollDeltaAccum = 0;
}
// Key queries
bool KeyboardMouseInput::IsKeyDown(int vk) const
{
if (vk < 0 || vk >= 256) return false;
return m_keyState[vk];
}
bool KeyboardMouseInput::IsKeyPressed(int vk) const
{
if (vk < 0 || vk >= 256) return false;
return m_keyState[vk] && !m_keyStatePrev[vk];
}
bool KeyboardMouseInput::IsKeyReleased(int vk) const
{
if (vk < 0 || vk >= 256) return false;
return !m_keyState[vk] && m_keyStatePrev[vk];
}
// Mouse button queries
bool KeyboardMouseInput::IsMouseDown(int btn) const
{
if (btn < 0 || btn >= 3) return false;
return m_mouseButtons[btn];
}
bool KeyboardMouseInput::IsMousePressed(int btn) const
{
if (btn < 0 || btn >= 3) return false;
return m_mouseButtons[btn] && !m_mouseButtonsPrev[btn];
}
bool KeyboardMouseInput::IsMouseReleased(int btn) const
{
if (btn < 0 || btn >= 3) return false;
return !m_mouseButtons[btn] && m_mouseButtonsPrev[btn];
}
// Delta queries
float KeyboardMouseInput::GetMouseDeltaX() const { return m_mouseDeltaX; }
float KeyboardMouseInput::GetMouseDeltaY() const { return m_mouseDeltaY; }
int KeyboardMouseInput::GetScrollDelta() const { return m_scrollDelta; }
// Mouse capture
void KeyboardMouseInput::SetCapture(bool capture)
{
if (capture == m_captured) return;
m_captured = capture;
if (capture)
{
ShowCursor(FALSE);
RECT rect;
GetClientRect(m_hWnd, &rect);
POINT topLeft = { rect.left, rect.top };
POINT bottomRight = { rect.right, rect.bottom };
ClientToScreen(m_hWnd, &topLeft);
ClientToScreen(m_hWnd, &bottomRight);
RECT screenRect = { topLeft.x, topLeft.y, bottomRight.x, bottomRight.y };
ClipCursor(&screenRect);
CenterCursor();
// Flush accumulated deltas so the snap-to-center doesn't cause a jump
m_mouseDeltaXAccum = 0.0f;
m_mouseDeltaYAccum = 0.0f;
}
else
{
ShowCursor(TRUE);
ClipCursor(NULL);
}
}
bool KeyboardMouseInput::IsCaptured() const { return m_captured; }
void KeyboardMouseInput::CenterCursor()
{
RECT rect;
GetClientRect(m_hWnd, &rect);
POINT center = { (rect.left + rect.right) / 2, (rect.top + rect.bottom) / 2 };
ClientToScreen(m_hWnd, &center);
SetCursorPos(center.x, center.y);
}
#endif // _WINDOWS64

View File

@@ -0,0 +1,76 @@
#pragma once
#ifdef _WINDOWS64
#include <windows.h>
// HID usage page and usage for raw input registration
#ifndef HID_USAGE_PAGE_GENERIC
#define HID_USAGE_PAGE_GENERIC ((USHORT)0x01)
#endif
#ifndef HID_USAGE_GENERIC_MOUSE
#define HID_USAGE_GENERIC_MOUSE ((USHORT)0x02)
#endif
class KeyboardMouseInput
{
public:
KeyboardMouseInput();
~KeyboardMouseInput();
void Init(HWND hWnd);
void Tick();
void EndFrame();
// Called from WndProc
void OnKeyDown(WPARAM vk);
void OnKeyUp(WPARAM vk);
void OnRawMouseInput(LPARAM lParam);
void OnMouseButton(int button, bool down);
void OnMouseWheel(int delta);
void ClearAllState();
// Key state queries (call after Tick)
bool IsKeyDown(int vk) const;
bool IsKeyPressed(int vk) const;
bool IsKeyReleased(int vk) const;
// Mouse button queries: 0=left, 1=right, 2=middle
bool IsMouseDown(int btn) const;
bool IsMousePressed(int btn) const;
bool IsMouseReleased(int btn) const;
// Mouse deltas (consumed each Tick)
float GetMouseDeltaX() const;
float GetMouseDeltaY() const;
int GetScrollDelta() const;
// Mouse capture for FPS look
void SetCapture(bool capture);
bool IsCaptured() const;
private:
void CenterCursor();
bool m_keyState[256];
bool m_keyStatePrev[256];
bool m_mouseButtons[3];
bool m_mouseButtonsPrev[3];
float m_mouseDeltaX;
float m_mouseDeltaY;
float m_mouseDeltaXAccum;
float m_mouseDeltaYAccum;
int m_scrollDelta;
int m_scrollDeltaAccum;
bool m_captured;
HWND m_hWnd;
bool m_initialized;
};
extern KeyboardMouseInput KMInput;
#endif // _WINDOWS64

View File

@@ -339,6 +339,63 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
case WM_DESTROY:
PostQuitMessage(0);
break;
// Keyboard/Mouse input handling
case WM_KEYDOWN:
if (!(lParam & 0x40000000)) // ignore auto-repeat
KMInput.OnKeyDown(wParam);
break;
case WM_KEYUP:
KMInput.OnKeyUp(wParam);
break;
case WM_SYSKEYDOWN:
if (wParam == VK_MENU) // Alt key
{
if (!(lParam & 0x40000000))
KMInput.OnKeyDown(wParam);
return 0; // prevent default Alt behavior
}
return DefWindowProc(hWnd, message, wParam, lParam);
case WM_SYSKEYUP:
if (wParam == VK_MENU)
{
KMInput.OnKeyUp(wParam);
return 0;
}
return DefWindowProc(hWnd, message, wParam, lParam);
case WM_INPUT:
KMInput.OnRawMouseInput(lParam);
break;
case WM_LBUTTONDOWN:
KMInput.OnMouseButton(0, true);
break;
case WM_LBUTTONUP:
KMInput.OnMouseButton(0, false);
break;
case WM_RBUTTONDOWN:
KMInput.OnMouseButton(1, true);
break;
case WM_RBUTTONUP:
KMInput.OnMouseButton(1, false);
break;
case WM_MBUTTONDOWN:
KMInput.OnMouseButton(2, true);
break;
case WM_MBUTTONUP:
KMInput.OnMouseButton(2, false);
break;
case WM_MOUSEWHEEL:
KMInput.OnMouseWheel(GET_WHEEL_DELTA_WPARAM(wParam));
break;
case WM_ACTIVATE:
if (LOWORD(wParam) == WA_INACTIVE)
KMInput.SetCapture(false);
break;
case WM_KILLFOCUS:
KMInput.SetCapture(false);
KMInput.ClearAllState();
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
@@ -715,6 +772,9 @@ int APIENTRY _tWinMain(_In_ HINSTANCE hInstance,
// Set the number of possible joypad layouts that the user can switch between, and the number of actions
InputManager.Initialise(1,3,MINECRAFT_ACTION_MAX, ACTION_MAX_MENU);
// Initialize keyboard/mouse input
KMInput.Init(g_hWnd);
// Set the default joypad action mappings for Minecraft
DefineActions();
InputManager.SetJoypadMapVal(0,0);
@@ -940,6 +1000,7 @@ int APIENTRY _tWinMain(_In_ HINSTANCE hInstance,
app.UpdateTime();
PIXBeginNamedEvent(0,"Input manager tick");
InputManager.Tick();
KMInput.Tick();
PIXEndNamedEvent();
PIXBeginNamedEvent(0,"Profile manager tick");
// ProfileManager.Tick();
@@ -1067,6 +1128,27 @@ int APIENTRY _tWinMain(_In_ HINSTANCE hInstance,
RenderManager.Present();
ui.CheckMenuDisplayed();
// Update mouse capture: capture when in-game and no menu is open
{
static bool altToggleSuppressCapture = false;
bool shouldCapture = app.GetGameStarted() && !ui.GetMenuDisplayed(0);
// Left Alt key toggles capture on/off for debugging
if (KMInput.IsKeyPressed(VK_MENU))
{
if (KMInput.IsCaptured()) { KMInput.SetCapture(false); altToggleSuppressCapture = true; }
else if (shouldCapture) { KMInput.SetCapture(true); altToggleSuppressCapture = false; }
}
else if (!shouldCapture)
{
if (KMInput.IsCaptured()) KMInput.SetCapture(false);
altToggleSuppressCapture = false;
}
else if (shouldCapture && !KMInput.IsCaptured() && GetFocus() == g_hWnd && !altToggleSuppressCapture)
{
KMInput.SetCapture(true);
}
}
#if 0
PIXBeginNamedEvent(0,"Profile load check");
// has the game defined profile data been changed (by a profile load)
@@ -1158,6 +1240,8 @@ int APIENTRY _tWinMain(_In_ HINSTANCE hInstance,
// Fix for #7318 - Title crashes after short soak in the leaderboards menu
// A memory leak was caused because the icon renderer kept creating new Vec3's because the pool wasn't reset
Vec3::resetPool();
KMInput.EndFrame();
}
// Free resources, unregister custom classes, and exit.

View File

@@ -174,10 +174,11 @@ typedef XUID GameSessionUID;
#include "Durango\4JLibs\inc\4J_Render.h"
#include "Durango\4JLibs\inc\4J_Storage.h"
#elif defined _WINDOWS64
#include "Windows64\4JLibs\inc\4J_Input.h"
#include "Windows64\4JLibs\inc\4J_Input.h"
#include "Windows64\4JLibs\inc\4J_Profile.h"
#include "Windows64\4JLibs\inc\4J_Render.h"
#include "Windows64\4JLibs\inc\4J_Storage.h"
#include "Windows64\KeyboardMouseInput.h"
#elif defined __PSVITA__
#include "PSVita\4JLibs\inc\4J_Input.h"
#include "PSVita\4JLibs\inc\4J_Profile.h"