aboutsummaryrefslogtreecommitdiff
path: root/Minecraft.Client
diff options
context:
space:
mode:
authorKevin <115616336+lag@users.noreply.github.com>2026-03-06 09:52:28 -0600
committerGitHub <noreply@github.com>2026-03-06 09:52:28 -0600
commitea65542c1b63d7ee37025837bf205e55ace0c863 (patch)
tree0ba5abdfdbf055d11bd85a460b98b51f2c9c9904 /Minecraft.Client
parent1755cd58bebf19053c6b4bbf9915b07237e1c14e (diff)
Add Chat / Pastes / Formatting (#682)
* Initial fixes for ContainerSetSlotPacket and CraftItemPacket * Chat: paste, history, § formatting, 1-9 block when open (Windows64) Made-with: Cursor * static_cast refactor
Diffstat (limited to 'Minecraft.Client')
-rw-r--r--Minecraft.Client/ChatScreen.cpp126
-rw-r--r--Minecraft.Client/ChatScreen.h22
-rw-r--r--Minecraft.Client/ClientConnection.cpp3
-rw-r--r--Minecraft.Client/Common/UI/UIComponent_Chat.cpp8
-rw-r--r--Minecraft.Client/Common/UI/UIScene_HUD.cpp8
-rw-r--r--Minecraft.Client/Font.cpp162
-rw-r--r--Minecraft.Client/Font.h10
-rw-r--r--Minecraft.Client/Gui.cpp15
-rw-r--r--Minecraft.Client/GuiComponent.cpp39
-rw-r--r--Minecraft.Client/GuiComponent.h1
-rw-r--r--Minecraft.Client/PlayerConnection.cpp32
-rw-r--r--Minecraft.Client/Screen.cpp130
-rw-r--r--Minecraft.Client/Screen.h5
-rw-r--r--Minecraft.Client/Windows64/KeyboardMouseInput.cpp8
-rw-r--r--Minecraft.Client/Windows64/KeyboardMouseInput.h2
-rw-r--r--Minecraft.Client/Windows64/Windows64_Minecraft.cpp33
16 files changed, 455 insertions, 149 deletions
diff --git a/Minecraft.Client/ChatScreen.cpp b/Minecraft.Client/ChatScreen.cpp
index b68e6cac..543cab76 100644
--- a/Minecraft.Client/ChatScreen.cpp
+++ b/Minecraft.Client/ChatScreen.cpp
@@ -1,14 +1,27 @@
#include "stdafx.h"
#include "ChatScreen.h"
+#include "ClientConnection.h"
+#include "Font.h"
#include "MultiplayerLocalPlayer.h"
#include "..\Minecraft.World\SharedConstants.h"
#include "..\Minecraft.World\StringHelpers.h"
+#include "..\Minecraft.World\ChatPacket.h"
const wstring ChatScreen::allowedChars = SharedConstants::acceptableLetters;
+vector<wstring> ChatScreen::s_chatHistory;
+int ChatScreen::s_historyIndex = -1;
+wstring ChatScreen::s_historyDraft;
+
+bool ChatScreen::isAllowedChatChar(wchar_t c)
+{
+ return c >= 0x20 && (c == L'\u00A7' || allowedChars.empty() || allowedChars.find(c) != wstring::npos);
+}
ChatScreen::ChatScreen()
{
frame = 0;
+ cursorIndex = 0;
+ s_historyIndex = -1;
}
void ChatScreen::init()
@@ -24,6 +37,50 @@ void ChatScreen::removed()
void ChatScreen::tick()
{
frame++;
+ if (cursorIndex > static_cast<int>(message.length()))
+ cursorIndex = static_cast<int>(message.length());
+}
+
+void ChatScreen::handlePasteRequest()
+{
+ wstring pasted = Screen::getClipboard();
+ for (size_t i = 0; i < pasted.length() && static_cast<int>(message.length()) < SharedConstants::maxChatLength; i++)
+ {
+ if (isAllowedChatChar(pasted[i]))
+ {
+ message.insert(cursorIndex, 1, pasted[i]);
+ cursorIndex++;
+ }
+ }
+}
+
+void ChatScreen::applyHistoryMessage()
+{
+ message = s_historyIndex >= 0 ? s_chatHistory[s_historyIndex] : s_historyDraft;
+ cursorIndex = static_cast<int>(message.length());
+}
+
+void ChatScreen::handleHistoryUp()
+{
+ if (s_chatHistory.empty()) return;
+ if (s_historyIndex == -1)
+ {
+ s_historyDraft = message;
+ s_historyIndex = static_cast<int>(s_chatHistory.size()) - 1;
+ }
+ else if (s_historyIndex > 0)
+ s_historyIndex--;
+ applyHistoryMessage();
+}
+
+void ChatScreen::handleHistoryDown()
+{
+ if (s_chatHistory.empty()) return;
+ if (s_historyIndex < static_cast<int>(s_chatHistory.size()) - 1)
+ s_historyIndex++;
+ else
+ s_historyIndex = -1;
+ applyHistoryMessage();
}
void ChatScreen::keyPressed(wchar_t ch, int eventKey)
@@ -35,31 +92,67 @@ void ChatScreen::keyPressed(wchar_t ch, int eventKey)
}
if (eventKey == Keyboard::KEY_RETURN)
{
- wstring msg = trimString(message);
- if (msg.length() > 0)
+ wstring trim = trimString(message);
+ if (trim.length() > 0)
{
- wstring trim = trimString(message);
if (!minecraft->handleClientSideCommand(trim))
{
- minecraft->player->chat(trim);
+ MultiplayerLocalPlayer* mplp = dynamic_cast<MultiplayerLocalPlayer*>(minecraft->player.get());
+ if (mplp && mplp->connection)
+ mplp->connection->send(shared_ptr<ChatPacket>(new ChatPacket(trim)));
+ }
+ if (s_chatHistory.empty() || s_chatHistory.back() != trim)
+ {
+ s_chatHistory.push_back(trim);
+ if (s_chatHistory.size() > CHAT_HISTORY_MAX)
+ s_chatHistory.erase(s_chatHistory.begin());
}
}
minecraft->setScreen(NULL);
return;
}
- if (eventKey == Keyboard::KEY_BACK && message.length() > 0) message = message.substr(0, message.length() - 1);
- if (allowedChars.find(ch) >= 0 && message.length() < SharedConstants::maxChatLength)
+ if (eventKey == Keyboard::KEY_UP) { handleHistoryUp(); return; }
+ if (eventKey == Keyboard::KEY_DOWN) { handleHistoryDown(); return; }
+ if (eventKey == Keyboard::KEY_LEFT)
{
- message += ch;
+ if (cursorIndex > 0)
+ cursorIndex--;
+ return;
+ }
+ if (eventKey == Keyboard::KEY_RIGHT)
+ {
+ if (cursorIndex < static_cast<int>(message.length()))
+ cursorIndex++;
+ return;
+ }
+ if (eventKey == Keyboard::KEY_BACK && cursorIndex > 0)
+ {
+ message.erase(cursorIndex - 1, 1);
+ cursorIndex--;
+ return;
+ }
+ if (isAllowedChatChar(ch) && static_cast<int>(message.length()) < SharedConstants::maxChatLength)
+ {
+ message.insert(cursorIndex, 1, ch);
+ cursorIndex++;
}
-
}
void ChatScreen::render(int xm, int ym, float a)
{
fill(2, height - 14, width - 2, height - 2, 0x80000000);
- drawString(font, L"> " + message + (frame / 6 % 2 == 0 ? L"_" : L""), 4, height - 12, 0xe0e0e0);
-
+ const wstring prefix = L"> ";
+ int x = 4;
+ drawString(font, prefix, x, height - 12, 0xe0e0e0);
+ x += font->width(prefix);
+ wstring beforeCursor = message.substr(0, cursorIndex);
+ wstring afterCursor = message.substr(cursorIndex);
+ drawStringLiteral(font, beforeCursor, x, height - 12, 0xe0e0e0);
+ x += font->widthLiteral(beforeCursor);
+ if (frame / 6 % 2 == 0)
+ drawString(font, L"_", x, height - 12, 0xe0e0e0);
+ x += font->width(L"_");
+ drawStringLiteral(font, afterCursor, x, height - 12, 0xe0e0e0);
Screen::render(xm, ym, a);
}
@@ -71,13 +164,15 @@ void ChatScreen::mouseClicked(int x, int y, int buttonNum)
{
if (message.length() > 0 && message[message.length()-1]!=L' ')
{
- message += L" ";
+ message = message.substr(0, cursorIndex) + L" " + message.substr(cursorIndex);
+ cursorIndex++;
}
- message += minecraft->gui->selectedName;
- unsigned int maxLength = SharedConstants::maxChatLength;
- if (message.length() > maxLength)
+ size_t nameLen = minecraft->gui->selectedName.length();
+ size_t insertLen = (message.length() + nameLen <= SharedConstants::maxChatLength) ? nameLen : (SharedConstants::maxChatLength - message.length());
+ if (insertLen > 0)
{
- message = message.substr(0, maxLength);
+ message = message.substr(0, cursorIndex) + minecraft->gui->selectedName.substr(0, insertLen) + message.substr(cursorIndex);
+ cursorIndex += static_cast<int>(insertLen);
}
}
else
@@ -85,5 +180,4 @@ void ChatScreen::mouseClicked(int x, int y, int buttonNum)
Screen::mouseClicked(x, y, buttonNum);
}
}
-
} \ No newline at end of file
diff --git a/Minecraft.Client/ChatScreen.h b/Minecraft.Client/ChatScreen.h
index d7158478..c4e37a93 100644
--- a/Minecraft.Client/ChatScreen.h
+++ b/Minecraft.Client/ChatScreen.h
@@ -1,21 +1,33 @@
#pragma once
#include "Screen.h"
+#include <vector>
using namespace std;
class ChatScreen : public Screen
{
protected:
wstring message;
+ int cursorIndex;
+ void applyHistoryMessage();
+
private:
int frame;
+ static const size_t CHAT_HISTORY_MAX = 100;
+ static std::vector<wstring> s_chatHistory;
+ static int s_historyIndex;
+ static wstring s_historyDraft;
+ static const wstring allowedChars;
+ static bool isAllowedChatChar(wchar_t c);
public:
- ChatScreen(); //4J added
+ ChatScreen();
virtual void init();
- virtual void removed();
- virtual void tick();
-private:
- static const wstring allowedChars;
+ virtual void removed();
+ virtual void tick();
+ virtual void handlePasteRequest();
+ virtual void handleHistoryUp();
+ virtual void handleHistoryDown();
+
protected:
void keyPressed(wchar_t ch, int eventKey);
public:
diff --git a/Minecraft.Client/ClientConnection.cpp b/Minecraft.Client/ClientConnection.cpp
index 9b9bb86a..315a8032 100644
--- a/Minecraft.Client/ClientConnection.cpp
+++ b/Minecraft.Client/ClientConnection.cpp
@@ -1441,6 +1441,9 @@ void ClientConnection::handleChat(shared_ptr<ChatPacket> packet)
switch(packet->m_messageType)
{
+ case ChatPacket::e_ChatCustom:
+ message = (packet->m_stringArgs.size() >= 1) ? packet->m_stringArgs[0] : L"";
+ break;
case ChatPacket::e_ChatBedOccupied:
message = app.GetString(IDS_TILE_BED_OCCUPIED);
break;
diff --git a/Minecraft.Client/Common/UI/UIComponent_Chat.cpp b/Minecraft.Client/Common/UI/UIComponent_Chat.cpp
index 98b4f165..901b5a77 100644
--- a/Minecraft.Client/Common/UI/UIComponent_Chat.cpp
+++ b/Minecraft.Client/Common/UI/UIComponent_Chat.cpp
@@ -55,10 +55,16 @@ void UIComponent_Chat::handleTimerComplete(int id)
float opacity = pGui->getOpacity(m_iPad, i);
if( opacity > 0 )
{
+#ifdef _WINDOWS64
+ // Chat drawn by Gui::render with color codes. Hides Iggy chat to avoid double chats.
+ m_controlLabelBackground[i].setOpacity(0);
+ 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->getMessage(m_iPad,i) );
-
+#endif
anyVisible = true;
}
else
diff --git a/Minecraft.Client/Common/UI/UIScene_HUD.cpp b/Minecraft.Client/Common/UI/UIScene_HUD.cpp
index c3d52cf9..e01757ab 100644
--- a/Minecraft.Client/Common/UI/UIScene_HUD.cpp
+++ b/Minecraft.Client/Common/UI/UIScene_HUD.cpp
@@ -753,10 +753,16 @@ void UIScene_HUD::handleTimerComplete(int id)
float opacity = pGui->getOpacity(m_iPad, i);
if( opacity > 0 )
{
+#ifdef _WINDOWS64
+ // Chat drawn by Gui::render with color codes. Hides Iggy chat to avoid double chats.
+ m_controlLabelBackground[i].setOpacity(0);
+ 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"" );
-
+#endif
anyVisible = true;
}
else
diff --git a/Minecraft.Client/Font.cpp b/Minecraft.Client/Font.cpp
index 8a90711b..51b50ca1 100644
--- a/Minecraft.Client/Font.cpp
+++ b/Minecraft.Client/Font.cpp
@@ -21,6 +21,10 @@ Font::Font(Options *options, const wstring& name, Textures* textures, bool enfor
enforceUnicodeSheet = false;
bidirectional = false;
xPos = yPos = 0.0f;
+ m_bold = false;
+ m_italic = false;
+ m_underline = false;
+ m_strikethrough = false;
// Set up member variables
m_cols = cols;
@@ -126,6 +130,22 @@ Font::~Font()
}
#endif
+void Font::renderStyleLine(float x0, float y0, float x1, float y1)
+{
+ Tesselator* t = Tesselator::getInstance();
+ float u = 0.0f, v = 0.0f;
+ t->begin();
+ t->tex(u, v);
+ t->vertex(x0, y1, 0.0f);
+ t->tex(u, v);
+ t->vertex(x1, y1, 0.0f);
+ t->tex(u, v);
+ t->vertex(x1, y0, 0.0f);
+ t->tex(u, v);
+ t->vertex(x0, y0, 0.0f);
+ t->end();
+}
+
void Font::renderCharacter(wchar_t c)
{
float xOff = c % m_cols * m_charWidth;
@@ -137,37 +157,47 @@ void Font::renderCharacter(wchar_t c)
float fontWidth = m_cols * m_charWidth;
float fontHeight = m_rows * m_charHeight;
- Tesselator *t = Tesselator::getInstance();
- // 4J Stu - Changed to a quad so that we can use within a command buffer
-#if 1
+ const float shear = m_italic ? (height * 0.25f) : 0.0f;
+ float x0 = xPos, x1 = xPos + width + shear;
+ float y0 = yPos, y1 = yPos + height;
+
+ Tesselator *t = Tesselator::getInstance();
t->begin();
t->tex(xOff / fontWidth, (yOff + 7.99f) / fontHeight);
- t->vertex(xPos, yPos + height, 0.0f);
-
+ t->vertex(x0, y1, 0.0f);
t->tex((xOff + width) / fontWidth, (yOff + 7.99f) / fontHeight);
- t->vertex(xPos + width, yPos + height, 0.0f);
-
+ t->vertex(x1, y1, 0.0f);
t->tex((xOff + width) / fontWidth, yOff / fontHeight);
- t->vertex(xPos + width, yPos, 0.0f);
-
+ t->vertex(x1, y0, 0.0f);
t->tex(xOff / fontWidth, yOff / fontHeight);
- t->vertex(xPos, yPos, 0.0f);
-
+ t->vertex(x0, y0, 0.0f);
t->end();
-#else
- t->begin(GL_TRIANGLE_STRIP);
- t->tex(xOff / 128.0F, yOff / 128.0F);
- t->vertex(xPos, yPos, 0.0f);
- t->tex(xOff / 128.0F, (yOff + 7.99f) / 128.0F);
- t->vertex(xPos, yPos + 7.99f, 0.0f);
- t->tex((xOff + width) / 128.0F, yOff / 128.0F);
- t->vertex(xPos + width, yPos, 0.0f);
- t->tex((xOff + width) / 128.0F, (yOff + 7.99f) / 128.0F);
- t->vertex(xPos + width, yPos + 7.99f, 0.0f);
- t->end();
-#endif
- xPos += (float) charWidths[c];
+ if (m_bold)
+ {
+ float dx = 1.0f;
+ t->begin();
+ t->tex(xOff / fontWidth, (yOff + 7.99f) / fontHeight);
+ t->vertex(x0 + dx, y1, 0.0f);
+ t->tex((xOff + width) / fontWidth, (yOff + 7.99f) / fontHeight);
+ t->vertex(x1 + dx, y1, 0.0f);
+ t->tex((xOff + width) / fontWidth, yOff / fontHeight);
+ t->vertex(x1 + dx, y0, 0.0f);
+ t->tex(xOff / fontWidth, yOff / fontHeight);
+ t->vertex(x0 + dx, y0, 0.0f);
+ t->end();
+ }
+
+ if (m_underline)
+ renderStyleLine(x0, y1 - 1.0f, xPos + static_cast<float>(charWidths[c]), y1);
+
+ if (m_strikethrough)
+ {
+ float mid = y0 + height * 0.5f;
+ renderStyleLine(x0, mid - 0.5f, xPos + static_cast<float>(charWidths[c]), mid + 0.5f);
+ }
+
+ xPos += static_cast<float>(charWidths[c]);
}
void Font::drawShadow(const wstring& str, int x, int y, int color)
@@ -176,6 +206,26 @@ void Font::drawShadow(const wstring& str, int x, int y, int color)
draw(str, x, y, color, false);
}
+void Font::drawShadowLiteral(const wstring& str, int x, int y, int color)
+{
+ int shadowColor = (color & 0xFCFCFC) >> 2 | (color & 0xFF000000);
+ drawLiteral(str, x + 1, y + 1, shadowColor);
+ drawLiteral(str, x, y, color);
+}
+
+void Font::drawLiteral(const wstring& str, int x, int y, int color)
+{
+ if (str.empty()) return;
+ if ((color & 0xFC000000) == 0) color |= 0xFF000000;
+ textures->bindTexture(m_textureLocation);
+ glColor4f((color >> 16 & 255) / 255.0F, (color >> 8 & 255) / 255.0F, (color & 255) / 255.0F, (color >> 24 & 255) / 255.0F);
+ xPos = static_cast<float>(x);
+ yPos = static_cast<float>(y);
+ wstring cleanStr = sanitize(str);
+ for (size_t i = 0; i < cleanStr.length(); ++i)
+ renderCharacter(cleanStr.at(i));
+}
+
void Font::drawShadowWordWrap(const wstring &str, int x, int y, int w, int color, int h)
{
drawWordWrapInternal(str, x + 1, y + 1, w, color, true, h);
@@ -193,24 +243,38 @@ wstring Font::reorderBidi(const wstring &str)
return str;
}
+static bool isSectionFormatCode(wchar_t ca)
+{
+ if ((ca >= L'0' && ca <= L'9') || (ca >= L'a' && ca <= L'f') || (ca >= L'A' && ca <= L'F'))
+ return true;
+ wchar_t l = static_cast<wchar_t>(ca | 32);
+ return l == L'l' || l == L'o' || l == L'n' || l == L'm' || l == L'r' || l == L'k';
+}
+
void Font::draw(const wstring &str, bool dropShadow)
{
// Bind the texture
textures->bindTexture(m_textureLocation);
bool noise = false;
+ m_bold = m_italic = m_underline = m_strikethrough = false;
wstring cleanStr = sanitize(str);
- for (int i = 0; i < (int)cleanStr.length(); ++i)
+ for (int i = 0; i < static_cast<int>(cleanStr.length()); ++i)
{
// Map character
wchar_t c = cleanStr.at(i);
if (c == 167 && i + 1 < cleanStr.length())
{
- // 4J - following block was:
- // int colorN = L"0123456789abcdefk".indexOf(str.toLowerCase().charAt(i + 1));
wchar_t ca = cleanStr[i+1];
+ if (!isSectionFormatCode(ca))
+ {
+ renderCharacter(167);
+ renderCharacter(ca);
+ i += 1;
+ continue;
+ }
int colorN = 16;
if(( ca >= L'0' ) && (ca <= L'9')) colorN = ca - L'0';
else if(( ca >= L'a' ) && (ca <= L'f')) colorN = (ca - L'a') + 10;
@@ -218,7 +282,13 @@ void Font::draw(const wstring &str, bool dropShadow)
if (colorN == 16)
{
- noise = true;
+ wchar_t l = static_cast<wchar_t>(ca | 32);
+ if (l == L'l') m_bold = true;
+ else if (l == L'o') m_italic = true;
+ else if (l == L'n') m_underline = true;
+ else if (l == L'm') m_strikethrough = true;
+ else if (l == L'r') m_bold = m_italic = m_underline = m_strikethrough = noise = false;
+ else if (l == L'k') noise = true;
}
else
{
@@ -280,20 +350,34 @@ int Font::width(const wstring& str)
{
wchar_t c = cleanStr.at(i);
- if(c == 167)
+ if (c == 167)
{
- // Ignore the character used to define coloured text
- ++i;
+ if (i + 1 < cleanStr.length() && isSectionFormatCode(cleanStr[i+1]))
+ ++i;
+ else
+ {
+ len += charWidths[167];
+ if (i + 1 < cleanStr.length())
+ len += charWidths[static_cast<unsigned>(cleanStr[++i])];
+ }
}
else
- {
len += charWidths[c];
- }
}
return len;
}
+int Font::widthLiteral(const wstring& str)
+{
+ wstring cleanStr = sanitize(str);
+ if (cleanStr == L"") return 0;
+ int len = 0;
+ for (size_t i = 0; i < cleanStr.length(); ++i)
+ len += charWidths[static_cast<unsigned>(cleanStr.at(i))];
+ return len;
+}
+
wstring Font::sanitize(const wstring& str)
{
wstring sb = str;
@@ -467,7 +551,7 @@ void Font::setBidirectional(bool bidirectional)
bool Font::AllCharactersValid(const wstring &str)
{
- for (int i = 0; i < (int)str.length(); ++i)
+ for (int i = 0; i < static_cast<int>(str.length()); ++i)
{
wchar_t c = str.at(i);
@@ -512,15 +596,15 @@ void Font::renderFakeCB(IntBuffer *ib)
float uo = (0.0f) / 128.0f;
float vo = (0.0f) / 128.0f;
- t->vertexUV((float)(0), (float)( 0 + s), (float)( 0), (float)( ix / 128.0f + uo), (float)( (iy + s) / 128.0f + vo));
- t->vertexUV((float)(0 + s), (float)( 0 + s), (float)( 0), (float)( (ix + s) / 128.0f + uo), (float)( (iy + s) / 128.0f + vo));
- t->vertexUV((float)(0 + s), (float)( 0), (float)( 0), (float)( (ix + s) / 128.0f + uo), (float)( iy / 128.0f + vo));
- t->vertexUV((float)(0), (float)( 0), (float)( 0), (float)( ix / 128.0f + uo), (float)( iy / 128.0f + vo));
+ t->vertexUV(static_cast<float>(0), static_cast<float>(0 + s), static_cast<float>(0), static_cast<float>(ix / 128.0f + uo), static_cast<float>((iy + s) / 128.0f + vo));
+ t->vertexUV(static_cast<float>(0 + s), static_cast<float>(0 + s), static_cast<float>(0), static_cast<float>((ix + s) / 128.0f + uo), static_cast<float>((iy + s) / 128.0f + vo));
+ t->vertexUV(static_cast<float>(0 + s), static_cast<float>(0), static_cast<float>(0), static_cast<float>((ix + s) / 128.0f + uo), static_cast<float>(iy / 128.0f + vo));
+ t->vertexUV(static_cast<float>(0), static_cast<float>(0), static_cast<float>(0), static_cast<float>(ix / 128.0f + uo), static_cast<float>(iy / 128.0f + vo));
// target.colorBlit(texture, x + xo, y, color, ix, iy,
// charWidths[chars[i]], 8);
t->end();
- glTranslatef((float)charWidths[i], 0, 0);
+ glTranslatef(static_cast<float>(charWidths[i]), 0, 0);
}
else
{
diff --git a/Minecraft.Client/Font.h b/Minecraft.Client/Font.h
index 18d9bf91..3d25880d 100644
--- a/Minecraft.Client/Font.h
+++ b/Minecraft.Client/Font.h
@@ -21,6 +21,12 @@ private:
float xPos;
float yPos;
+ // § format state (bold, italic, underline, strikethrough); set during draw(), reset by §r
+ bool m_bold;
+ bool m_italic;
+ bool m_underline;
+ bool m_strikethrough;
+
bool enforceUnicodeSheet; // use unicode sheet for ascii
bool bidirectional; // use bidi to flip strings
@@ -41,9 +47,11 @@ public:
private:
void renderCharacter(wchar_t c); // 4J added
+ void renderStyleLine(float x0, float y0, float x1, float y1); // solid line for underline/strikethrough
public:
void drawShadow(const wstring& str, int x, int y, int color);
+ void drawShadowLiteral(const wstring& str, int x, int y, int color); // draw without interpreting § codes
void drawShadowWordWrap(const wstring &str, int x, int y, int w, int color, int h); // 4J Added h param
void draw(const wstring &str, int x, int y, int color);
/**
@@ -58,11 +66,13 @@ private:
void draw(const wstring &str, bool dropShadow);
void draw(const wstring& str, int x, int y, int color, bool dropShadow);
+ void drawLiteral(const wstring& str, int x, int y, int color); // no § parsing
int MapCharacter(wchar_t c); // 4J added
bool CharacterExists(wchar_t c); // 4J added
public:
int width(const wstring& str);
+ int widthLiteral(const wstring& str); // width without skipping § codes (for chat input)
wstring sanitize(const wstring& str);
void drawWordWrap(const wstring &string, int x, int y, int w, int col, int h); // 4J Added h param
diff --git a/Minecraft.Client/Gui.cpp b/Minecraft.Client/Gui.cpp
index 1199c138..365ddeac 100644
--- a/Minecraft.Client/Gui.cpp
+++ b/Minecraft.Client/Gui.cpp
@@ -971,15 +971,10 @@ void Gui::render(float a, bool mouseFree, int xMouse, int yMouse)
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glDisable(GL_ALPHA_TEST);
-// 4J Stu - We have moved the chat text to a xui
-#if 0
+#if defined(_WINDOWS64)
glPushMatrix();
- // 4J-PB we need to move this up a bit because we've moved the quick select
- //glTranslatef(0, ((float)screenHeight) - 48, 0);
- glTranslatef(0.0f, (float)(screenHeight - iSafezoneYHalf - iTooltipsYOffset - 16 - 3 + 22) - 24.0f, 0.0f);
- // glScalef(1.0f / ssc.scale, 1.0f / ssc.scale, 1);
+ glTranslatef(0.0f, static_cast<float>(screenHeight - iSafezoneYHalf - iTooltipsYOffset - 16 - 3 + 22) - 24.0f, 0.0f);
- // 4J-PB - we need gui messages for each of the possible 4 splitscreen players
if(bDisplayGui)
{
int iPad=minecraft->player->GetXboxPad();
@@ -993,23 +988,21 @@ void Gui::render(float a, bool mouseFree, int xMouse, int yMouse)
if (t < 0) t = 0;
if (t > 1) t = 1;
t = t * t;
- int alpha = (int) (255 * t);
+ int alpha = static_cast<int>(255 * t);
if (isChatting) alpha = 255;
if (alpha > 0)
{
int x = iSafezoneXHalf+2;
- int y = -((int)i) * 9;
+ int y = -(static_cast<int>(i)) * 9;
if(bTwoPlayerSplitscreen)
{
y+= iHeightOffset;
}
wstring msg = guiMessages[iPad][i].string;
- // 4J-PB - fill the black bar across the whole screen, otherwise it looks odd due to the safe area
this->fill(0, y - 1, screenWidth/fScaleFactorWidth, y + 8, (alpha / 2) << 24);
glEnable(GL_BLEND);
-
font->drawShadow(msg, iSafezoneXHalf+4, y, 0xffffff + (alpha << 24));
}
}
diff --git a/Minecraft.Client/GuiComponent.cpp b/Minecraft.Client/GuiComponent.cpp
index 92abf36d..c6b5f518 100644
--- a/Minecraft.Client/GuiComponent.cpp
+++ b/Minecraft.Client/GuiComponent.cpp
@@ -48,10 +48,10 @@ void GuiComponent::fill(int x0, int y0, int x1, int y1, int col)
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glColor4f(r, g, b, a);
t->begin();
- t->vertex((float)(x0), (float)( y1), (float)( 0));
- t->vertex((float)(x1), (float)( y1), (float)( 0));
- t->vertex((float)(x1), (float)( y0), (float)( 0));
- t->vertex((float)(x0), (float)( y0), (float)( 0));
+ t->vertex(static_cast<float>(x0), static_cast<float>(y1), static_cast<float>(0));
+ t->vertex(static_cast<float>(x1), static_cast<float>(y1), static_cast<float>(0));
+ t->vertex(static_cast<float>(x1), static_cast<float>(y0), static_cast<float>(0));
+ t->vertex(static_cast<float>(x0), static_cast<float>(y0), static_cast<float>(0));
t->end();
glEnable(GL_TEXTURE_2D);
glDisable(GL_BLEND);
@@ -77,11 +77,11 @@ void GuiComponent::fillGradient(int x0, int y0, int x1, int y1, int col1, int co
Tesselator *t = Tesselator::getInstance();
t->begin();
t->color(r1, g1, b1, a1);
- t->vertex((float)(x1), (float)( y0), blitOffset);
- t->vertex((float)(x0), (float)( y0), blitOffset);
+ t->vertex(static_cast<float>(x1), static_cast<float>(y0), blitOffset);
+ t->vertex(static_cast<float>(x0), static_cast<float>(y0), blitOffset);
t->color(r2, g2, b2, a2);
- t->vertex((float)(x0), (float)( y1), blitOffset);
- t->vertex((float)(x1), (float)( y1), blitOffset);
+ t->vertex(static_cast<float>(x0), static_cast<float>(y1), blitOffset);
+ t->vertex(static_cast<float>(x1), static_cast<float>(y1), blitOffset);
t->end();
glShadeModel(GL_FLAT);
@@ -105,6 +105,11 @@ void GuiComponent::drawString(Font *font, const wstring& str, int x, int y, int
font->drawShadow(str, x, y, color);
}
+void GuiComponent::drawStringLiteral(Font *font, const wstring& str, int x, int y, int color)
+{
+ font->drawShadowLiteral(str, x, y, color);
+}
+
void GuiComponent::blit(int x, int y, int sx, int sy, int w, int h)
{
float us = 1 / 256.0f;
@@ -117,20 +122,20 @@ void GuiComponent::blit(int x, int y, int sx, int sy, int w, int h)
const float extraShift = 0.75f;
// 4J - subtracting extraShift (actual screen pixels, so need to compensate for physical & game width) from each x & y coordinate to compensate for centre of pixels in directx vs openGL
- float dx = ( extraShift * (float)Minecraft::GetInstance()->width ) / (float)Minecraft::GetInstance()->width_phys;
+ float dx = ( extraShift * static_cast<float>(Minecraft::GetInstance()->width) ) / static_cast<float>(Minecraft::GetInstance()->width_phys);
// 4J - Also factor in the scaling from gui coordinate space to the screen. This varies based on user-selected gui scale, and whether we are in a viewport mode or not
dx /= Gui::currentGuiScaleFactor;
float dy = extraShift / Gui::currentGuiScaleFactor;
// Ensure that the x/y, width and height are actually pixel aligned at our current scale factor - in particular, for split screen mode with the default (3X)
// scale, we have an overall scale factor of 3 * 0.5 = 1.5, and so any odd pixels won't align
- float fx = (floorf((float)x * Gui::currentGuiScaleFactor)) / Gui::currentGuiScaleFactor;
- float fy = (floorf((float)y * Gui::currentGuiScaleFactor)) / Gui::currentGuiScaleFactor;
- float fw = (floorf((float)w * Gui::currentGuiScaleFactor)) / Gui::currentGuiScaleFactor;
- float fh = (floorf((float)h * Gui::currentGuiScaleFactor)) / Gui::currentGuiScaleFactor;
+ float fx = (floorf(static_cast<float>(x) * Gui::currentGuiScaleFactor)) / Gui::currentGuiScaleFactor;
+ float fy = (floorf(static_cast<float>(y) * Gui::currentGuiScaleFactor)) / Gui::currentGuiScaleFactor;
+ float fw = (floorf(static_cast<float>(w) * Gui::currentGuiScaleFactor)) / Gui::currentGuiScaleFactor;
+ float fh = (floorf(static_cast<float>(h) * Gui::currentGuiScaleFactor)) / Gui::currentGuiScaleFactor;
- t->vertexUV(fx + 0 - dx, fy + fh - dy, (float)( blitOffset), (float)( (sx + 0) * us), (float)( (sy + h) * vs));
- t->vertexUV(fx + fw - dx, fy + fh - dy, (float)( blitOffset), (float)( (sx + w) * us), (float)( (sy + h) * vs));
- t->vertexUV(fx + fw - dx, fy + 0 - dy, (float)( blitOffset), (float)( (sx + w) * us), (float)( (sy + 0) * vs));
- t->vertexUV(fx + 0 - dx, fy + 0 - dy, (float)( blitOffset), (float)( (sx + 0) * us), (float)( (sy + 0) * vs));
+ t->vertexUV(fx + 0 - dx, fy + fh - dy, static_cast<float>(blitOffset), static_cast<float>((sx + 0) * us), static_cast<float>((sy + h) * vs));
+ t->vertexUV(fx + fw - dx, fy + fh - dy, static_cast<float>(blitOffset), static_cast<float>((sx + w) * us), static_cast<float>((sy + h) * vs));
+ t->vertexUV(fx + fw - dx, fy + 0 - dy, static_cast<float>(blitOffset), static_cast<float>((sx + w) * us), static_cast<float>((sy + 0) * vs));
+ t->vertexUV(fx + 0 - dx, fy + 0 - dy, static_cast<float>(blitOffset), static_cast<float>((sx + 0) * us), static_cast<float>((sy + 0) * vs));
t->end();
} \ No newline at end of file
diff --git a/Minecraft.Client/GuiComponent.h b/Minecraft.Client/GuiComponent.h
index 7073db40..41496664 100644
--- a/Minecraft.Client/GuiComponent.h
+++ b/Minecraft.Client/GuiComponent.h
@@ -15,5 +15,6 @@ public:
GuiComponent(); // 4J added
void drawCenteredString(Font *font, const wstring& str, int x, int y, int color);
void drawString(Font *font, const wstring& str, int x, int y, int color);
+ void drawStringLiteral(Font* font, const wstring& str, int x, int y, int color);
void blit(int x, int y, int sx, int sy, int w, int h);
};
diff --git a/Minecraft.Client/PlayerConnection.cpp b/Minecraft.Client/PlayerConnection.cpp
index ab8ae20b..9404a5d6 100644
--- a/Minecraft.Client/PlayerConnection.cpp
+++ b/Minecraft.Client/PlayerConnection.cpp
@@ -21,6 +21,8 @@
#include "..\Minecraft.World\AABB.h"
#include "..\Minecraft.World\Pos.h"
#include "..\Minecraft.World\SharedConstants.h"
+#include "..\Minecraft.World\ChatPacket.h"
+#include "..\Minecraft.World\StringHelpers.h"
#include "..\Minecraft.World\Socket.h"
#include "..\Minecraft.World\Achievements.h"
#include "..\Minecraft.World\net.minecraft.h"
@@ -607,38 +609,26 @@ void PlayerConnection::handleSetCarriedItem(shared_ptr<SetCarriedItemPacket> pac
void PlayerConnection::handleChat(shared_ptr<ChatPacket> packet)
{
- // 4J - TODO
-#if 0
- wstring message = packet->message;
+ if (packet->m_stringArgs.empty()) return;
+ wstring message = trimString(packet->m_stringArgs[0]);
if (message.length() > SharedConstants::maxChatLength)
{
- disconnect(L"Chat message too long");
+ disconnect(DisconnectPacket::eDisconnect_None); // or a specific reason
return;
}
- message = message.trim();
- for (int i = 0; i < message.length(); i++)
- {
- if (SharedConstants.acceptableLetters.indexOf(message.charAt(i)) < 0 && (int) message.charAt(i) < 32)
- {
- disconnect(L"Illegal characters in chat");
- return;
- }
- }
-
- if (message.startsWith("/"))
+ // Optional: validate characters (acceptableLetters)
+ if (message.length() > 0 && message[0] == L'/')
{
handleCommand(message);
- } else {
- message = "<" + player.name + "> " + message;
- logger.info(message);
- server.players.broadcastAll(new ChatPacket(message));
+ return;
}
+ wstring formatted = L"<" + player->name + L"> " + message;
+ server->getPlayers()->broadcastAll(shared_ptr<ChatPacket>(new ChatPacket(formatted)));
chatSpamTickCount += SharedConstants::TICKS_PER_SECOND;
if (chatSpamTickCount > SharedConstants::TICKS_PER_SECOND * 10)
{
- disconnect("disconnect.spam");
+ disconnect(DisconnectPacket::eDisconnect_None); // spam
}
-#endif
}
void PlayerConnection::handleCommand(const wstring& message)
diff --git a/Minecraft.Client/Screen.cpp b/Minecraft.Client/Screen.cpp
index 131cf013..9b753146 100644
--- a/Minecraft.Client/Screen.cpp
+++ b/Minecraft.Client/Screen.cpp
@@ -1,6 +1,7 @@
#include "stdafx.h"
#include "Screen.h"
#include "Button.h"
+#include "ChatScreen.h"
#include "GuiParticles.h"
#include "Tesselator.h"
#include "Textures.h"
@@ -42,13 +43,32 @@ void Screen::keyPressed(wchar_t eventCharacter, int eventKey)
wstring Screen::getClipboard()
{
- // 4J - removed
- return NULL;
+#ifdef _WINDOWS64
+ if (!OpenClipboard(NULL)) return wstring();
+ HANDLE h = GetClipboardData(CF_UNICODETEXT);
+ wstring out;
+ if (h)
+ {
+ const wchar_t *p = reinterpret_cast<const wchar_t*>(GlobalLock(h));
+ if (p) { out = p; GlobalUnlock(h); }
+ }
+ CloseClipboard();
+ return out;
+#else
+ return wstring();
+#endif
}
void Screen::setClipboard(const wstring& str)
{
- // 4J - removed
+#ifdef _WINDOWS64
+ if (!OpenClipboard(NULL)) return;
+ EmptyClipboard();
+ size_t len = (str.length() + 1) * sizeof(wchar_t);
+ HGLOBAL h = GlobalAlloc(GMEM_MOVEABLE, len);
+ if (h) { memcpy(GlobalLock(h), str.c_str(), len); GlobalUnlock(h); SetClipboardData(CF_UNICODETEXT, h); }
+ CloseClipboard();
+#endif
}
void Screen::mouseClicked(int x, int y, int buttonNum)
@@ -121,34 +141,88 @@ void Screen::updateEvents()
}
}
- // Poll keyboard events
+ // Only drain WM_CHAR when this screen wants text input (e.g. ChatScreen); otherwise we'd steal keys from the game
+ if (dynamic_cast<ChatScreen*>(this) != nullptr)
+ {
+ wchar_t ch;
+ while (g_KBMInput.ConsumeChar(ch))
+ {
+ if (ch >= 0x20)
+ keyPressed(ch, -1);
+ else if (ch == 0x08)
+ keyPressed(0, Keyboard::KEY_BACK);
+ else if (ch == 0x0D)
+ keyPressed(0, Keyboard::KEY_RETURN);
+ }
+ }
+
+ // Arrow key repeat: deliver on first press (when key down and last==0) and while held (throttled)
+ static DWORD s_arrowLastTime[2] = { 0, 0 };
+ static bool s_arrowFirstRepeat[2] = { false, false };
+ const DWORD ARROW_REPEAT_DELAY_MS = 250;
+ const DWORD ARROW_REPEAT_INTERVAL_MS = 50;
+ DWORD now = GetTickCount();
+
+ // Poll keyboard events (special keys that may not come through WM_CHAR, e.g. Escape, arrows)
for (int vk = 0; vk < 256; vk++)
{
- if (g_KBMInput.IsKeyPressed(vk))
+ bool deliver = g_KBMInput.IsKeyPressed(vk);
+ if (vk == VK_LEFT || vk == VK_RIGHT)
{
- // Map Windows virtual key to the Keyboard constants used by Screen::keyPressed
- int mappedKey = -1;
- wchar_t ch = 0;
- if (vk == VK_ESCAPE) mappedKey = Keyboard::KEY_ESCAPE;
- else if (vk == VK_RETURN) mappedKey = Keyboard::KEY_RETURN;
- else if (vk == VK_BACK) mappedKey = Keyboard::KEY_BACK;
- else if (vk == VK_UP) mappedKey = Keyboard::KEY_UP;
- else if (vk == VK_DOWN) mappedKey = Keyboard::KEY_DOWN;
- else if (vk == VK_LEFT) mappedKey = Keyboard::KEY_LEFT;
- else if (vk == VK_RIGHT) mappedKey = Keyboard::KEY_RIGHT;
- else if (vk == VK_LSHIFT || vk == VK_RSHIFT) mappedKey = Keyboard::KEY_LSHIFT;
- else if (vk == VK_TAB) mappedKey = Keyboard::KEY_TAB;
- else if (vk >= 'A' && vk <= 'Z')
+ int idx = (vk == VK_LEFT) ? 0 : 1;
+ if (!g_KBMInput.IsKeyDown(vk))
{
- ch = (wchar_t)(vk - 'A' + L'a');
- if (g_KBMInput.IsKeyDown(VK_LSHIFT) || g_KBMInput.IsKeyDown(VK_RSHIFT)) ch = (wchar_t)vk;
+ s_arrowLastTime[idx] = 0;
+ s_arrowFirstRepeat[idx] = false;
}
- else if (vk >= '0' && vk <= '9') ch = (wchar_t)vk;
- else if (vk == VK_SPACE) ch = L' ';
+ else
+ {
+ DWORD last = s_arrowLastTime[idx];
+ if (last == 0)
+ deliver = true;
+ else if (!deliver)
+ {
+ DWORD interval = s_arrowFirstRepeat[idx] ? ARROW_REPEAT_INTERVAL_MS : ARROW_REPEAT_DELAY_MS;
+ if ((now - last) >= interval)
+ {
+ deliver = true;
+ s_arrowFirstRepeat[idx] = true;
+ }
+ }
+ if (deliver)
+ s_arrowLastTime[idx] = now;
+ }
+ }
+ // Escape: deliver when key is down so we don't miss it (IsKeyPressed can be one frame late)
+ if (vk == VK_ESCAPE && g_KBMInput.IsKeyDown(VK_ESCAPE))
+ deliver = true;
+ if (!deliver) continue;
- if (mappedKey != -1) keyPressed(ch, mappedKey);
- else if (ch != 0) keyPressed(ch, -1);
+ if (dynamic_cast<ChatScreen*>(this) != nullptr &&
+ (vk >= 'A' && vk <= 'Z' || vk >= '0' && vk <= '9' || vk == VK_SPACE || vk == VK_RETURN || vk == VK_BACK))
+ continue;
+ // Map to Screen::keyPressed
+ int mappedKey = -1;
+ wchar_t ch = 0;
+ if (vk == VK_ESCAPE) mappedKey = Keyboard::KEY_ESCAPE;
+ else if (vk == VK_RETURN) mappedKey = Keyboard::KEY_RETURN;
+ else if (vk == VK_BACK) mappedKey = Keyboard::KEY_BACK;
+ else if (vk == VK_UP) mappedKey = Keyboard::KEY_UP;
+ else if (vk == VK_DOWN) mappedKey = Keyboard::KEY_DOWN;
+ else if (vk == VK_LEFT) mappedKey = Keyboard::KEY_LEFT;
+ else if (vk == VK_RIGHT) mappedKey = Keyboard::KEY_RIGHT;
+ else if (vk == VK_LSHIFT || vk == VK_RSHIFT) mappedKey = Keyboard::KEY_LSHIFT;
+ else if (vk == VK_TAB) mappedKey = Keyboard::KEY_TAB;
+ else if (vk >= 'A' && vk <= 'Z')
+ {
+ ch = static_cast<wchar_t>(vk - 'A' + L'a');
+ if (g_KBMInput.IsKeyDown(VK_LSHIFT) || g_KBMInput.IsKeyDown(VK_RSHIFT)) ch = static_cast<wchar_t>(vk);
}
+ else if (vk >= '0' && vk <= '9') ch = static_cast<wchar_t>(vk);
+ else if (vk == VK_SPACE) ch = L' ';
+
+ if (mappedKey != -1) keyPressed(ch, mappedKey);
+ else if (ch != 0) keyPressed(ch, -1);
}
#else
/* 4J - TODO
@@ -232,10 +306,10 @@ void Screen::renderDirtBackground(int vo)
float s = 32;
t->begin();
t->color(0x404040);
- t->vertexUV((float)(0), (float)( height), (float)( 0), (float)( 0), (float)( height / s + vo));
- t->vertexUV((float)(width), (float)( height), (float)( 0), (float)( width / s), (float)( height / s + vo));
- t->vertexUV((float)(width), (float)( 0), (float)( 0), (float)( width / s), (float)( 0 + vo));
- t->vertexUV((float)(0), (float)( 0), (float)( 0), (float)( 0), (float)( 0 + vo));
+ t->vertexUV(static_cast<float>(0), static_cast<float>(height), static_cast<float>(0), static_cast<float>(0), static_cast<float>(height / s + vo));
+ t->vertexUV(static_cast<float>(width), static_cast<float>(height), static_cast<float>(0), static_cast<float>(width / s), static_cast<float>(height / s + vo));
+ t->vertexUV(static_cast<float>(width), static_cast<float>(0), static_cast<float>(0), static_cast<float>(width / s), static_cast<float>(0 + vo));
+ t->vertexUV(static_cast<float>(0), static_cast<float>(0), static_cast<float>(0), static_cast<float>(0), static_cast<float>(0 + vo));
t->end();
#endif
}
diff --git a/Minecraft.Client/Screen.h b/Minecraft.Client/Screen.h
index 50deb1d0..6b2cb945 100644
--- a/Minecraft.Client/Screen.h
+++ b/Minecraft.Client/Screen.h
@@ -36,9 +36,12 @@ protected:
virtual void mouseReleased(int x, int y, int buttonNum);
virtual void buttonClicked(Button *button);
public:
- virtual void init(Minecraft *minecraft, int width, int height);
+ virtual void init(Minecraft *minecraft, int width, int height);
virtual void setSize(int width, int height);
virtual void init();
+ virtual void handlePasteRequest() {}
+ virtual void handleHistoryUp() {}
+ virtual void handleHistoryDown() {}
virtual void updateEvents();
virtual void mouseEvent();
virtual void keyboardEvent();
diff --git a/Minecraft.Client/Windows64/KeyboardMouseInput.cpp b/Minecraft.Client/Windows64/KeyboardMouseInput.cpp
index fe3c3919..d3e40806 100644
--- a/Minecraft.Client/Windows64/KeyboardMouseInput.cpp
+++ b/Minecraft.Client/Windows64/KeyboardMouseInput.cpp
@@ -257,8 +257,8 @@ bool KeyboardMouseInput::IsMouseButtonReleased(int button) const
void KeyboardMouseInput::ConsumeMouseDelta(float &dx, float &dy)
{
- dx = (float)m_mouseDeltaAccumX;
- dy = (float)m_mouseDeltaAccumY;
+ dx = static_cast<float>(m_mouseDeltaAccumX);
+ dy = static_cast<float>(m_mouseDeltaAccumY);
m_mouseDeltaAccumX = 0;
m_mouseDeltaAccumY = 0;
}
@@ -375,12 +375,12 @@ float KeyboardMouseInput::GetMoveY() const
float KeyboardMouseInput::GetLookX(float sensitivity) const
{
- return (float)m_mouseDeltaX * sensitivity;
+ return static_cast<float>(m_mouseDeltaX) * sensitivity;
}
float KeyboardMouseInput::GetLookY(float sensitivity) const
{
- return (float)(-m_mouseDeltaY) * sensitivity;
+ return static_cast<float>(-m_mouseDeltaY) * sensitivity;
}
void KeyboardMouseInput::OnChar(wchar_t c)
diff --git a/Minecraft.Client/Windows64/KeyboardMouseInput.h b/Minecraft.Client/Windows64/KeyboardMouseInput.h
index fff924bf..0f14dfa1 100644
--- a/Minecraft.Client/Windows64/KeyboardMouseInput.h
+++ b/Minecraft.Client/Windows64/KeyboardMouseInput.h
@@ -143,4 +143,4 @@ private:
extern KeyboardMouseInput g_KBMInput;
-#endif // _WINDOWS64
+#endif
diff --git a/Minecraft.Client/Windows64/Windows64_Minecraft.cpp b/Minecraft.Client/Windows64/Windows64_Minecraft.cpp
index fa4b8366..208fd3f7 100644
--- a/Minecraft.Client/Windows64/Windows64_Minecraft.cpp
+++ b/Minecraft.Client/Windows64/Windows64_Minecraft.cpp
@@ -22,6 +22,9 @@
#include "..\..\Minecraft.World\net.minecraft.world.level.tile.h"
#include "..\ClientConnection.h"
+#include "..\Minecraft.h"
+#include "..\ChatScreen.h"
+#include "KeyboardMouseInput.h"
#include "..\User.h"
#include "..\..\Minecraft.World\Socket.h"
#include "..\..\Minecraft.World\ThreadName.h"
@@ -572,14 +575,28 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
case WM_CHAR:
// Buffer typed characters so UIScene_Keyboard can dispatch them to the Iggy Flash player
if (wParam >= 0x20 || wParam == 0x08 || wParam == 0x0D) // printable chars + backspace + enter
- g_KBMInput.OnChar((wchar_t)wParam);
+ g_KBMInput.OnChar(static_cast<wchar_t>(wParam));
break;
case WM_KEYDOWN:
case WM_SYSKEYDOWN:
{
- int vk = (int)wParam;
- if (lParam & 0x40000000) break; // ignore auto-repeat
+ int vk = static_cast<int>(wParam);
+ if ((lParam & 0x40000000) && vk != VK_LEFT && vk != VK_RIGHT && vk != VK_BACK)
+ break;
+#ifdef _WINDOWS64
+ Minecraft* pm = Minecraft::GetInstance();
+ ChatScreen* chat = pm && pm->screen ? dynamic_cast<ChatScreen*>(pm->screen) : nullptr;
+ if (chat)
+ {
+ if (vk == 'V' && (GetKeyState(VK_CONTROL) & 0x8000))
+ { chat->handlePasteRequest(); break; }
+ if ((vk == VK_UP || vk == VK_DOWN) && !(lParam & 0x40000000))
+ { if (vk == VK_UP) chat->handleHistoryUp(); else chat->handleHistoryDown(); break; }
+ if (vk >= '1' && vk <= '9') // Prevent hotkey conflicts
+ break;
+ }
+#endif
if (vk == VK_SHIFT)
vk = (MapVirtualKey((lParam >> 16) & 0xFF, MAPVK_VSC_TO_VK_EX) == VK_RSHIFT) ? VK_RSHIFT : VK_LSHIFT;
else if (vk == VK_CONTROL)
@@ -592,7 +609,7 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
case WM_KEYUP:
case WM_SYSKEYUP:
{
- int vk = (int)wParam;
+ int vk = static_cast<int>(wParam);
if (vk == VK_SHIFT)
vk = (MapVirtualKey((lParam >> 16) & 0xFF, MAPVK_VSC_TO_VK_EX) == VK_RSHIFT) ? VK_RSHIFT : VK_LSHIFT;
else if (vk == VK_CONTROL)
@@ -1612,6 +1629,14 @@ int APIENTRY _tWinMain(_In_ HINSTANCE hInstance,
}
}
+ // Open chat
+ if (g_KBMInput.IsKeyPressed('T') && app.GetGameStarted() && !ui.GetMenuDisplayed(0) && pMinecraft->screen == NULL)
+ {
+ g_KBMInput.ClearCharBuffer();
+ pMinecraft->setScreen(new ChatScreen());
+ SetFocus(g_hWnd);
+ }
+
#if 0
// has the game defined profile data been changed (by a profile load)
if(app.uiGameDefinedDataChangedBitmask!=0)