feat: Scrollable chat (#1493)

* chat scrolling

* allow escape to close chat instead of opening pause
This commit is contained in:
DrPerkyLegit 2026-04-12 23:50:16 -04:00 committed by GitHub
parent 744048f455
commit c7014f6b18
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 58 additions and 10 deletions

View file

@ -11,6 +11,7 @@ const wstring ChatScreen::allowedChars = SharedConstants::acceptableLetters;
vector<wstring> ChatScreen::s_chatHistory;
int ChatScreen::s_historyIndex = -1;
wstring ChatScreen::s_historyDraft;
int ChatScreen::s_chatIndex = 0;
bool ChatScreen::isAllowedChatChar(wchar_t c)
{
@ -22,6 +23,8 @@ ChatScreen::ChatScreen()
frame = 0;
cursorIndex = 0;
s_historyIndex = -1;
ChatScreen::s_chatIndex = 0;
}
void ChatScreen::init()
@ -83,6 +86,20 @@ void ChatScreen::handleHistoryDown()
applyHistoryMessage();
}
int ChatScreen::getChatIndex()
{
return ChatScreen::s_chatIndex;
}
void ChatScreen::correctChatIndex(int newChatIndex) {
ChatScreen::s_chatIndex = newChatIndex;
}
void ChatScreen::setWheelValue(int wheel) {
ChatScreen::s_chatIndex += wheel;
if (ChatScreen::s_chatIndex < 0) ChatScreen::s_chatIndex = 0;
}
void ChatScreen::keyPressed(wchar_t ch, int eventKey)
{
if (eventKey == Keyboard::KEY_ESCAPE)
@ -131,6 +148,7 @@ void ChatScreen::keyPressed(wchar_t ch, int eventKey)
cursorIndex--;
return;
}
if (isAllowedChatChar(ch) && static_cast<int>(message.length()) < SharedConstants::maxChatLength)
{
message.insert(cursorIndex, 1, ch);

View file

@ -16,6 +16,7 @@ private:
static std::vector<wstring> s_chatHistory;
static int s_historyIndex;
static wstring s_historyDraft;
static int s_chatIndex;
static const wstring allowedChars;
static bool isAllowedChatChar(wchar_t c);
@ -28,6 +29,9 @@ public:
virtual void handleHistoryUp();
virtual void handleHistoryDown();
static int getChatIndex();
static void correctChatIndex(int newChatIndex);
static void setWheelValue(int wheel);
protected:
void keyPressed(wchar_t ch, int eventKey);
public:

View file

@ -1,5 +1,6 @@
#include "stdafx.h"
#include "UIController.h"
#include <ChatScreen.h>
#include "UI.h"
#include "UIScene.h"
#include "UIControl_Slider.h"
@ -1428,6 +1429,9 @@ void UIController::handleKeyPress(unsigned int iPad, unsigned int key)
}
#endif
if (key == 4) ChatScreen::setWheelValue(1);
if (key == 5) ChatScreen::setWheelValue(-1);
if(pressed) app.DebugPrintf("Pressed %d\n",key);
if(released) app.DebugPrintf("Released %d\n",key);
// Repeat handling

View file

@ -9,6 +9,7 @@
#include "..\..\EnderDragonRenderer.h"
#include "..\..\..\Minecraft.World\net.minecraft.world.inventory.h"
#include "..\..\..\Minecraft.World\StringHelpers.h"
#include <ChatScreen.h>
UIScene_HUD::UIScene_HUD(int iPad, void *initData, UILayer *parentLayer) : UIScene(iPad, parentLayer)
{
@ -761,16 +762,31 @@ void UIScene_HUD::render(S32 width, S32 height, C4JRender::eViewportType viewpor
void UIScene_HUD::handleTimerComplete(int id)
{
Minecraft *pMinecraft = Minecraft::GetInstance();
bool isChatOpen = (dynamic_cast<ChatScreen*>(pMinecraft->getScreen()) != nullptr);
bool anyVisible = false;
if(pMinecraft->localplayers[m_iPad]!= nullptr)
{
Gui *pGui = pMinecraft->gui;
//DWORD messagesToDisplay = min( CHAT_LINES_COUNT, pGui->getMessagesCount(m_iPad) );
for( unsigned int i = 0; i < CHAT_LINES_COUNT; ++i )
DWORD totalMessages = pGui->getMessagesCount(m_iPad);
DWORD messagesToDisplay = min( CHAT_LINES_COUNT, totalMessages);
DWORD maxScroll = max(0, totalMessages - messagesToDisplay);
bool canScroll = messagesToDisplay < totalMessages;
int startIndex = (canScroll && isChatOpen ? ChatScreen::getChatIndex() : 0);
if (startIndex > maxScroll) {
ChatScreen::correctChatIndex(maxScroll);
startIndex = maxScroll;
}
app.DebugPrintf("handleTimerComplete: %d | %d | %d\n", maxScroll, startIndex, totalMessages);
for( unsigned int i = 0; i < messagesToDisplay; ++i )
{
float opacity = pGui->getOpacity(m_iPad, i);
if( opacity > 0 )
unsigned int msgIndex = startIndex + i;
float opacity = pGui->getOpacity(m_iPad, msgIndex);
if( opacity > 0 || isChatOpen)
{
#if 0 // def _WINDOWS64 // Use Iggy chat until Gui::render has visual parity
// Chat drawn by Gui::render with color codes. Hides Iggy chat to avoid double chats.
@ -778,9 +794,10 @@ void UIScene_HUD::handleTimerComplete(int id)
m_labelChatText[i].setOpacity(0);
m_labelChatText[i].setLabel(L"");
#else
m_controlLabelBackground[i].setOpacity(opacity);
m_labelChatText[i].setOpacity(opacity);
m_labelChatText[i].setLabel( pGui->getMessagesCount(m_iPad) ? pGui->getMessage(m_iPad,i) : L"" );
m_controlLabelBackground[i].setOpacity((isChatOpen ? 1 : opacity));
m_labelChatText[i].setOpacity((isChatOpen ? 1 : opacity));
m_labelChatText[i].setLabel(pGui->getMessage(m_iPad, msgIndex));
#endif
anyVisible = true;
}

View file

@ -17,6 +17,7 @@ private:
static const int m_iMaxMessageWidth = 280;
static ItemRenderer *itemRenderer;
vector<GuiMessage> guiMessages[XUSER_MAX_COUNT];
int chatIndex = 0;
Random *random;
Minecraft *minecraft;

View file

@ -1537,8 +1537,12 @@ void Minecraft::run_middle()
// Utility keys always work regardless of KBM active state
if(g_KBMInput.IsKeyPressed(KeyboardMouseInput::KEY_PAUSE) && !ui.GetMenuDisplayed(i))
{
localplayers[i]->ullButtonsPressed|=1LL<<MINECRAFT_ACTION_PAUSEMENU;
app.DebugPrintf("PAUSE PRESSED (keyboard) - ipad = %d\n",i);
if (dynamic_cast<ChatScreen*>(getScreen()) != nullptr) {
setScreen(nullptr);
} else {
localplayers[i]->ullButtonsPressed|=1LL<<MINECRAFT_ACTION_PAUSEMENU;
app.DebugPrintf("PAUSE PRESSED (keyboard) - ipad = %d\n",i);
}
}
if(g_KBMInput.IsKeyPressed(KeyboardMouseInput::KEY_THIRD_PERSON))

View file

@ -161,7 +161,7 @@ void Screen::updateEvents()
static bool s_arrowFirstRepeat[2] = { false, false };
const DWORD ARROW_REPEAT_DELAY_MS = 250;
const DWORD ARROW_REPEAT_INTERVAL_MS = 50;
DWORD now = GetTickCount();
DWORD now = GetTickCount64();
// Poll keyboard events (special keys that may not come through WM_CHAR, e.g. Escape, arrows)
for (int vk = 0; vk < 256; vk++)