Fix issues relating to SDL and wxWidgets interaction in Atlas.
This fixes the transfer of key inputs from WxWidgets to SDL, making it possible to type in the in-game GUI from Atlas. Also fixes whitespace issues in some Atlas files. The following improvements are OSX specific: - fixes an SDL assertion related to unused subsystems in Atlas. - Remove the 'osxguiapplication' override. This fixes the editor starting up in the background and not accepting input when launched from in-game. - To prevent an issue with sdl/wxwidgets conflict when running from inside the game, actually boot a new instance (see #2427) Reported by: wik (Many thanks for your investigations) Tested by: trompetin17, Stan Fixes #2427 Fixes #2846 Differential Revision: https://code.wildfiregames.com/D2788 This was SVN commit r23926.
This commit is contained in:
parent
375c319639
commit
01118c1196
33
source/lib/sysdep/os/osx/osx_atlas.h
Normal file
33
source/lib/sysdep/os/osx/osx_atlas.h
Normal file
@ -0,0 +1,33 @@
|
||||
/* Copyright (C) 2020 Wildfire Games.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef OSX_ATLAS_H
|
||||
#define OSX_ATLAS_H
|
||||
|
||||
|
||||
/**
|
||||
* Runs a new pyrogenesis process with the -editor argument.
|
||||
* Necessary because SDL and WxWidgets conflict.
|
||||
*/
|
||||
void startNewAtlasProcess();
|
||||
|
||||
#endif // OSX_ATLAS_H
|
54
source/lib/sysdep/os/osx/osx_atlas.mm
Normal file
54
source/lib/sysdep/os/osx/osx_atlas.mm
Normal file
@ -0,0 +1,54 @@
|
||||
/* Copyright (C) 2020 Wildfire Games.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#import <AvailabilityMacros.h> // MAC_OS_X_VERSION_MIN_REQUIRED
|
||||
#import <AppKit/AppKit.h>
|
||||
|
||||
#import "osx_atlas.h"
|
||||
|
||||
#include <vector>
|
||||
#include "lib/types.h"
|
||||
#include "ps/CStr.h"
|
||||
|
||||
extern std::vector<CStr> g_modsLoaded;
|
||||
|
||||
void startNewAtlasProcess()
|
||||
{
|
||||
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
|
||||
|
||||
NSMutableArray *args = [[NSMutableArray alloc] init];
|
||||
[args addObject:@"--editor"];
|
||||
|
||||
// Pass mods on the command line.
|
||||
for (const CStr& mod : g_modsLoaded)
|
||||
{
|
||||
std::string arg = std::string("-mod=") + mod;
|
||||
[args addObject:[[NSString alloc] initWithUTF8String:arg.c_str()]];
|
||||
}
|
||||
|
||||
// Apple documents this as (deprecated) NSWorkspaceLaunchConfigurationKey, but that's not available in early SDKs.
|
||||
NSDictionary<NSString*, id> *params = @{ NSWorkspaceLaunchConfigurationArguments: args };
|
||||
|
||||
[[NSWorkspace sharedWorkspace] launchApplicationAtURL:[[NSRunningApplication currentApplication] executableURL] options:NSWorkspaceLaunchNewInstance configuration:params error:nil];
|
||||
|
||||
[pool drain];
|
||||
}
|
@ -86,6 +86,10 @@ that of Atlas depending on commandline parameters.
|
||||
#include <unistd.h> // geteuid
|
||||
#endif // OS_UNIX
|
||||
|
||||
#if OS_MACOSX
|
||||
#include "lib/sysdep/os/osx/osx_atlas.h"
|
||||
#endif
|
||||
|
||||
#if MSC_VERSION
|
||||
#include <process.h>
|
||||
#define getpid _getpid // Use the non-deprecated function name
|
||||
@ -719,8 +723,13 @@ static void RunGameOrAtlas(int argc, const char* argv[])
|
||||
|
||||
} while (g_Shutdown == ShutdownType::Restart);
|
||||
|
||||
#if OS_MACOSX
|
||||
if (g_Shutdown == ShutdownType::RestartAsAtlas)
|
||||
startNewAtlasProcess();
|
||||
#else
|
||||
if (g_Shutdown == ShutdownType::RestartAsAtlas)
|
||||
ATLAS_RunIfOnCmdLine(args, true);
|
||||
#endif
|
||||
|
||||
CXeromyces::Terminate();
|
||||
}
|
||||
|
@ -300,7 +300,8 @@ static void ReportSDL(const ScriptInterface& scriptInterface, JS::HandleValue se
|
||||
snprintf(version, ARRAY_SIZE(version), "%d.%d.%d", runtime.major, runtime.minor, runtime.patch);
|
||||
scriptInterface.SetProperty(settings, "sdl_runtime_version", version);
|
||||
|
||||
const char* backend = GetSDLSubsystem(g_VideoMode.GetWindow());
|
||||
// This is null in atlas (and further the call triggers an assertion).
|
||||
const char* backend = g_VideoMode.GetWindow() ? GetSDLSubsystem(g_VideoMode.GetWindow()) : "none";
|
||||
scriptInterface.SetProperty(settings, "sdl_video_backend", backend ? backend : "unknown");
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2017 Wildfire Games.
|
||||
/* Copyright (C) 2020 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
@ -180,13 +180,6 @@ class AtlasDLLApp : public wxApp
|
||||
{
|
||||
public:
|
||||
|
||||
#ifdef __WXOSX__
|
||||
virtual bool OSXIsGUIApplication()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
virtual bool OnInit()
|
||||
{
|
||||
// _CrtSetBreakAlloc(5632);
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2013 Wildfire Games.
|
||||
/* Copyright (C) 2020 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
@ -77,6 +77,8 @@ int GetSDLKeyFromWxKeyCode(int wxkey)
|
||||
case WXK_F14: return SDLK_F14;
|
||||
case WXK_F15: return SDLK_F15;
|
||||
|
||||
case WXK_BACK: return SDLK_BACKSPACE;
|
||||
case WXK_DELETE: return SDLK_DELETE;
|
||||
case WXK_NUMLOCK: return SDLK_NUMLOCKCLEAR;
|
||||
case WXK_SCROLL: return SDLK_SCROLLLOCK;
|
||||
// case WXK_: return SDLK_CAPSLOCK;
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2019 Wildfire Games.
|
||||
/* Copyright (C) 2020 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
@ -132,9 +132,7 @@ private:
|
||||
if (KeyScroll(evt, true))
|
||||
return;
|
||||
|
||||
// Slight hack: Only pass 'special' keys; normal keys will generate a translated Char event instead
|
||||
if (evt.GetKeyCode() >= 256)
|
||||
POST_MESSAGE(GuiKeyEvent, (GetSDLKeyFromWxKeyCode(evt.GetKeyCode()), evt.GetUnicodeKey(), true));
|
||||
POST_MESSAGE(GuiKeyEvent, (GetSDLKeyFromWxKeyCode(evt.GetKeyCode()), evt.GetUnicodeKey(), true));
|
||||
|
||||
evt.Skip();
|
||||
}
|
||||
@ -147,9 +145,7 @@ private:
|
||||
if (KeyScroll(evt, false))
|
||||
return;
|
||||
|
||||
// Slight hack: Only pass 'special' keys; normal keys will generate a translated Char event instead
|
||||
if (evt.GetKeyCode() >= 256)
|
||||
POST_MESSAGE(GuiKeyEvent, (GetSDLKeyFromWxKeyCode(evt.GetKeyCode()), evt.GetUnicodeKey(), false));
|
||||
POST_MESSAGE(GuiKeyEvent, (GetSDLKeyFromWxKeyCode(evt.GetKeyCode()), evt.GetUnicodeKey(), false));
|
||||
|
||||
evt.Skip();
|
||||
}
|
||||
@ -189,8 +185,8 @@ private:
|
||||
}
|
||||
else
|
||||
{
|
||||
// Slight hack: Only pass 'normal' keys; special keys will generate a KeyDown/KeyUp event instead
|
||||
if (evt.GetKeyCode() < 256)
|
||||
// Slight hack: Only pass 'alphanumeric' keys; special keys will generate a KeyDown/KeyUp event instead
|
||||
if (evt.GetKeyCode() >= 33 && evt.GetKeyCode() <= 126)
|
||||
POST_MESSAGE(GuiCharEvent, (GetSDLKeyFromWxKeyCode(evt.GetKeyCode()), evt.GetUnicodeKey()));
|
||||
|
||||
evt.Skip();
|
||||
@ -315,14 +311,14 @@ enum
|
||||
{
|
||||
ID_Quit = 1,
|
||||
|
||||
ID_New,
|
||||
ID_New,
|
||||
ID_Open,
|
||||
ID_Save,
|
||||
ID_SaveAs,
|
||||
ID_ImportHeightmap,
|
||||
|
||||
ID_Copy,
|
||||
ID_Paste,
|
||||
ID_Copy,
|
||||
ID_Paste,
|
||||
|
||||
ID_Wireframe,
|
||||
ID_MessageTrace,
|
||||
@ -345,7 +341,7 @@ BEGIN_EVENT_TABLE(ScenarioEditor, wxFrame)
|
||||
EVT_CLOSE(ScenarioEditor::OnClose)
|
||||
EVT_TIMER(wxID_ANY, ScenarioEditor::OnTimer)
|
||||
|
||||
EVT_MENU(ID_New, ScenarioEditor::OnNew)
|
||||
EVT_MENU(ID_New, ScenarioEditor::OnNew)
|
||||
EVT_MENU(ID_Open, ScenarioEditor::OnOpen)
|
||||
EVT_MENU(ID_Save, ScenarioEditor::OnSave)
|
||||
EVT_MENU(ID_SaveAs, ScenarioEditor::OnSaveAs)
|
||||
@ -355,8 +351,8 @@ BEGIN_EVENT_TABLE(ScenarioEditor, wxFrame)
|
||||
EVT_MENU(ID_Quit, ScenarioEditor::OnQuit)
|
||||
EVT_MENU(wxID_UNDO, ScenarioEditor::OnUndo)
|
||||
EVT_MENU(wxID_REDO, ScenarioEditor::OnRedo)
|
||||
EVT_MENU(ID_Copy, ScenarioEditor::OnCopy)
|
||||
EVT_MENU(ID_Paste, ScenarioEditor::OnPaste)
|
||||
EVT_MENU(ID_Copy, ScenarioEditor::OnCopy)
|
||||
EVT_MENU(ID_Paste, ScenarioEditor::OnPaste)
|
||||
|
||||
EVT_MENU(ID_Wireframe, ScenarioEditor::OnWireframe)
|
||||
EVT_MENU(ID_MessageTrace, ScenarioEditor::OnMessageTrace)
|
||||
@ -439,7 +435,7 @@ ScenarioEditor::ScenarioEditor(wxWindow* parent)
|
||||
wxMenu *menuFile = new wxMenu;
|
||||
menuBar->Append(menuFile, _("&File"));
|
||||
{
|
||||
menuFile->Append(ID_New, _("&New..."));
|
||||
menuFile->Append(ID_New, _("&New..."));
|
||||
menuFile->Append(ID_Open, _("&Open..."));
|
||||
menuFile->Append(ID_Save, _("&Save"));
|
||||
menuFile->Append(ID_SaveAs, _("Save &As..."));
|
||||
@ -459,14 +455,14 @@ ScenarioEditor::ScenarioEditor(wxWindow* parent)
|
||||
{
|
||||
menuEdit->Append(wxID_UNDO, _("&Undo"));
|
||||
menuEdit->Append(wxID_REDO, _("&Redo"));
|
||||
menuEdit->AppendSeparator();
|
||||
menuEdit->Append(ID_Copy, _("&Copy"));
|
||||
menuEdit->Enable(ID_Copy, false);
|
||||
menuEdit->Append(ID_Paste, _("&Paste"));
|
||||
menuEdit->Enable(ID_Paste, false);
|
||||
menuEdit->AppendSeparator();
|
||||
menuEdit->Append(ID_Copy, _("&Copy"));
|
||||
menuEdit->Enable(ID_Copy, false);
|
||||
menuEdit->Append(ID_Paste, _("&Paste"));
|
||||
menuEdit->Enable(ID_Paste, false);
|
||||
}
|
||||
|
||||
g_SelectedObjects.RegisterObserver(0, &ScenarioEditor::OnSelectedObjectsChange, this);
|
||||
g_SelectedObjects.RegisterObserver(0, &ScenarioEditor::OnSelectedObjectsChange, this);
|
||||
|
||||
GetCommandProc().SetEditMenu(menuEdit);
|
||||
GetCommandProc().Initialize();
|
||||
@ -636,13 +632,13 @@ float ScenarioEditor::GetSpeedModifier()
|
||||
|
||||
void ScenarioEditor::OnClose(wxCloseEvent& event)
|
||||
{
|
||||
if (event.CanVeto() && GetCommandProc().IsDirty())
|
||||
{
|
||||
if (wxMessageBox(_T("You have unsaved changes. Are you sure you want to quit?"), _T("Discard unsaved changes?"), wxICON_QUESTION | wxYES_NO) != wxYES)
|
||||
{
|
||||
event.Veto();
|
||||
return;
|
||||
}
|
||||
if (event.CanVeto() && GetCommandProc().IsDirty())
|
||||
{
|
||||
if (wxMessageBox(_T("You have unsaved changes. Are you sure you want to quit?"), _T("Discard unsaved changes?"), wxICON_QUESTION | wxYES_NO) != wxYES)
|
||||
{
|
||||
event.Veto();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
m_ToolManager.SetCurrentTool(_T(""));
|
||||
@ -698,16 +694,16 @@ void ScenarioEditor::OnRedo(wxCommandEvent&)
|
||||
|
||||
void ScenarioEditor::OnCopy(wxCommandEvent& WXUNUSED(event))
|
||||
{
|
||||
if (GetToolManager().GetCurrentToolName() == _T("TransformObject"))
|
||||
GetToolManager().GetCurrentTool()->OnCommand(_T("copy"), NULL);
|
||||
if (GetToolManager().GetCurrentToolName() == _T("TransformObject"))
|
||||
GetToolManager().GetCurrentTool()->OnCommand(_T("copy"), NULL);
|
||||
}
|
||||
|
||||
void ScenarioEditor::OnPaste(wxCommandEvent& WXUNUSED(event))
|
||||
{
|
||||
if (GetToolManager().GetCurrentToolName() != _T("TransformObject"))
|
||||
GetToolManager().SetCurrentTool(_T("TransformObject"), NULL);
|
||||
if (GetToolManager().GetCurrentToolName() != _T("TransformObject"))
|
||||
GetToolManager().SetCurrentTool(_T("TransformObject"), NULL);
|
||||
|
||||
GetToolManager().GetCurrentTool()->OnCommand(_T("paste"), NULL);
|
||||
GetToolManager().GetCurrentTool()->OnCommand(_T("paste"), NULL);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
@ -837,7 +833,7 @@ void ScenarioEditor::OnSave(wxCommandEvent& event)
|
||||
qPing qry;
|
||||
qry.Post();
|
||||
|
||||
GetCommandProc().MarkAsSaved();
|
||||
GetCommandProc().MarkAsSaved();
|
||||
}
|
||||
}
|
||||
|
||||
@ -861,7 +857,7 @@ void ScenarioEditor::OnSaveAs(wxCommandEvent& WXUNUSED(event))
|
||||
qPing qry;
|
||||
qry.Post();
|
||||
|
||||
GetCommandProc().MarkAsSaved();
|
||||
GetCommandProc().MarkAsSaved();
|
||||
}
|
||||
}
|
||||
|
||||
@ -978,7 +974,7 @@ void ScenarioEditor::OnDumpState(wxCommandEvent& event)
|
||||
|
||||
void ScenarioEditor::OnSelectedObjectsChange(const std::vector<ObjectID>& selectedObjects)
|
||||
{
|
||||
GetMenuBar()->Enable(ID_Copy, !selectedObjects.empty());
|
||||
GetMenuBar()->Enable(ID_Copy, !selectedObjects.empty());
|
||||
}
|
||||
|
||||
void ScenarioEditor::OnHelp(wxCommandEvent& event)
|
||||
@ -996,50 +992,50 @@ void ScenarioEditor::OnHelp(wxCommandEvent& event)
|
||||
|
||||
void ScenarioEditor::OnMenuOpen(wxMenuEvent& event)
|
||||
{
|
||||
// Ignore wxMSW system menu events, see https://trac.wildfiregames.com/ticket/5501
|
||||
const wxMenu* menu = event.GetMenu();
|
||||
if (!menu)
|
||||
return;
|
||||
// Ignore wxMSW system menu events, see https://trac.wildfiregames.com/ticket/5501
|
||||
const wxMenu* menu = event.GetMenu();
|
||||
if (!menu)
|
||||
return;
|
||||
|
||||
// This could be done far more elegantly if wxMenuItem had changeable id.
|
||||
wxMenu* pasteMenuItem = NULL;
|
||||
menu->FindItem(ID_Paste, &pasteMenuItem);
|
||||
// This could be done far more elegantly if wxMenuItem had changeable id.
|
||||
wxMenu* pasteMenuItem = NULL;
|
||||
menu->FindItem(ID_Paste, &pasteMenuItem);
|
||||
|
||||
GetMenuBar()->Enable(ID_Paste, false);
|
||||
GetMenuBar()->Enable(ID_Paste, false);
|
||||
|
||||
if (!pasteMenuItem)
|
||||
return;
|
||||
if (!pasteMenuItem)
|
||||
return;
|
||||
|
||||
wxString content;
|
||||
if (wxTheClipboard->Open())
|
||||
{
|
||||
if (wxTheClipboard->IsSupported(wxDF_TEXT))
|
||||
{
|
||||
wxTextDataObject data;
|
||||
wxTheClipboard->GetData(data);
|
||||
content = data.GetText();
|
||||
}
|
||||
wxString content;
|
||||
if (wxTheClipboard->Open())
|
||||
{
|
||||
if (wxTheClipboard->IsSupported(wxDF_TEXT))
|
||||
{
|
||||
wxTextDataObject data;
|
||||
wxTheClipboard->GetData(data);
|
||||
content = data.GetText();
|
||||
}
|
||||
|
||||
wxTheClipboard->Close();
|
||||
}
|
||||
wxTheClipboard->Close();
|
||||
}
|
||||
|
||||
if (content.empty())
|
||||
return;
|
||||
if (content.empty())
|
||||
return;
|
||||
|
||||
wxInputStream* is = new wxStringInputStream(content);
|
||||
wxXmlDocument doc;
|
||||
{
|
||||
wxLogNull stopComplaining;
|
||||
static_cast<void>(stopComplaining);
|
||||
if (!doc.Load(*is))
|
||||
return;
|
||||
}
|
||||
wxInputStream* is = new wxStringInputStream(content);
|
||||
wxXmlDocument doc;
|
||||
{
|
||||
wxLogNull stopComplaining;
|
||||
static_cast<void>(stopComplaining);
|
||||
if (!doc.Load(*is))
|
||||
return;
|
||||
}
|
||||
|
||||
wxXmlNode* root = doc.GetRoot();
|
||||
if (!root || root->GetName() != wxT("Entities"))
|
||||
return;
|
||||
wxXmlNode* root = doc.GetRoot();
|
||||
if (!root || root->GetName() != wxT("Entities"))
|
||||
return;
|
||||
|
||||
GetMenuBar()->Enable(ID_Paste, true);
|
||||
GetMenuBar()->Enable(ID_Paste, true);
|
||||
}
|
||||
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2019 Wildfire Games.
|
||||
/* Copyright (C) 2020 Wildfire Games.
|
||||
* This file is part of 0 A.D.
|
||||
*
|
||||
* 0 A.D. is free software: you can redistribute it and/or modify
|
||||
@ -198,16 +198,20 @@ MESSAGEHANDLER(GuiKeyEvent)
|
||||
|
||||
MESSAGEHANDLER(GuiCharEvent)
|
||||
{
|
||||
// wxWidgets has special Char events but SDL doesn't, so convert it to
|
||||
// a keydown+keyup sequence. (We do the conversion here instead of on
|
||||
// the wx side to avoid nondeterministic behaviour caused by async messaging.)
|
||||
|
||||
// Simulate special 'text input' events in the SDL
|
||||
// This isn't quite compatible with WXWidget's handling,
|
||||
// so to avoid trouble we only send 'letter-like' ASCII input.
|
||||
SDL_Event_ ev = { { 0 } };
|
||||
ev.ev.type = SDL_KEYDOWN;
|
||||
ev.ev.key.keysym.sym = (SDL_Keycode)(int)msg->sdlkey;
|
||||
ev.ev.type = SDL_TEXTEDITING;
|
||||
ev.ev.text.type = SDL_TEXTEDITING;
|
||||
ev.ev.text.text[0] = (char)msg->sdlkey;
|
||||
ev.ev.text.text[1] = (char)0;
|
||||
in_dispatch_event(&ev);
|
||||
|
||||
ev.ev.type = SDL_KEYUP;
|
||||
ev.ev.type = SDL_TEXTINPUT;
|
||||
ev.ev.text.type = SDL_TEXTINPUT;
|
||||
ev.ev.text.text[0] = (char)msg->sdlkey;
|
||||
ev.ev.text.text[1] = (char)0;
|
||||
in_dispatch_event(&ev);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user