Skip to content

Commit a64a441

Browse files
authored
Merge pull request #264 from scratchcpp/event_whenkeypressed_block
Implement when key pressed block
2 parents bb7382f + 0aafc1f commit a64a441

File tree

7 files changed

+65
-3
lines changed

7 files changed

+65
-3
lines changed

include/scratchcpp/iengine.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,9 @@ class LIBSCRATCHCPP_EXPORT IEngine
210210
/* Registers the given "when I start as clone" script. */
211211
virtual void addCloneInitScript(std::shared_ptr<Block> hatBlock) = 0;
212212

213+
/* Registers the given "when key pressed" script. */
214+
virtual void addKeyPressScript(std::shared_ptr<Block> hatBlock, std::string keyName) = 0;
215+
213216
/*! Returns the list of targets. */
214217
virtual const std::vector<std::shared_ptr<Target>> &targets() const = 0;
215218

src/blocks/eventblocks.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,15 @@ void EventBlocks::registerBlocks(IEngine *engine)
2626
engine->addCompileFunction(this, "event_broadcastandwait", &compileBroadcastAndWait);
2727
engine->addCompileFunction(this, "event_whenbroadcastreceived", &compileWhenBroadcastReceived);
2828
engine->addCompileFunction(this, "event_whenbackdropswitchesto", &compileWhenBackdropSwitchesTo);
29+
engine->addCompileFunction(this, "event_whenkeypressed", &compileWhenKeyPressed);
2930

3031
// Inputs
3132
engine->addInput(this, "BROADCAST_INPUT", BROADCAST_INPUT);
3233

3334
// Fields
3435
engine->addField(this, "BROADCAST_OPTION", BROADCAST_OPTION);
3536
engine->addField(this, "BACKDROP", BACKDROP);
37+
engine->addField(this, "KEY_OPTION", KEY_OPTION);
3638
}
3739

3840
void EventBlocks::compileBroadcast(Compiler *compiler)
@@ -84,6 +86,12 @@ void EventBlocks::compileWhenBackdropSwitchesTo(Compiler *compiler)
8486
}
8587
}
8688

89+
void EventBlocks::compileWhenKeyPressed(Compiler *compiler)
90+
{
91+
// NOTE: Field values don't have to be registered because keys are referenced by their names
92+
compiler->engine()->addKeyPressScript(compiler->block(), compiler->field(KEY_OPTION)->value().toString());
93+
}
94+
8795
unsigned int EventBlocks::broadcast(VirtualMachine *vm)
8896
{
8997
vm->engine()->broadcast(vm->engine()->findBroadcast(vm->getInput(0, 1)->toString()), vm);

src/blocks/eventblocks.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@ class EventBlocks : public IBlockSection
2222
enum Fields
2323
{
2424
BROADCAST_OPTION,
25-
BACKDROP
25+
BACKDROP,
26+
KEY_OPTION
2627
};
2728

2829
std::string name() const override;
@@ -33,6 +34,7 @@ class EventBlocks : public IBlockSection
3334
static void compileBroadcastAndWait(Compiler *compiler);
3435
static void compileWhenBroadcastReceived(Compiler *compiler);
3536
static void compileWhenBackdropSwitchesTo(Compiler *compiler);
37+
static void compileWhenKeyPressed(Compiler *compiler);
3638

3739
static unsigned int broadcast(VirtualMachine *vm);
3840
static unsigned int broadcastByIndex(VirtualMachine *vm);

src/engine/internal/engine.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -620,6 +620,22 @@ void Engine::addCloneInitScript(std::shared_ptr<Block> hatBlock)
620620
}
621621
}
622622

623+
void Engine::addKeyPressScript(std::shared_ptr<Block> hatBlock, std::string keyName)
624+
{
625+
std::transform(keyName.begin(), keyName.end(), keyName.begin(), ::tolower);
626+
Script *script = m_scripts[hatBlock].get();
627+
auto it = m_whenKeyPressedScripts.find(keyName);
628+
629+
if (it == m_whenKeyPressedScripts.cend())
630+
m_whenKeyPressedScripts[keyName] = { script };
631+
else {
632+
auto &scripts = it->second;
633+
634+
if (std::find(scripts.begin(), scripts.end(), script) == scripts.cend())
635+
scripts.push_back(script);
636+
}
637+
}
638+
623639
const std::vector<std::shared_ptr<Target>> &Engine::targets() const
624640
{
625641
return m_targets;

src/engine/internal/engine.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,8 +83,8 @@ class Engine : public IEngine
8383
int findBroadcastById(const std::string &broadcastId) const override;
8484

8585
void addBroadcastScript(std::shared_ptr<Block> whenReceivedBlock, Broadcast *broadcast) override;
86-
8786
void addCloneInitScript(std::shared_ptr<Block> hatBlock) override;
87+
void addKeyPressScript(std::shared_ptr<Block> hatBlock, std::string keyName) override;
8888

8989
const std::vector<std::shared_ptr<Target>> &targets() const override;
9090
void setTargets(const std::vector<std::shared_ptr<Target>> &newTargets) override;
@@ -120,6 +120,7 @@ class Engine : public IEngine
120120
std::unordered_map<Broadcast *, std::vector<Script *>> m_broadcastMap;
121121
std::unordered_map<Broadcast *, std::vector<std::pair<VirtualMachine *, VirtualMachine *>>> m_runningBroadcastMap; // source script, "when received" script
122122
std::unordered_map<Target *, std::vector<Script *>> m_cloneInitScriptsMap; // target (no clones), "when I start as a clone" scripts
123+
std::unordered_map<std::string, std::vector<Script *>> m_whenKeyPressedScripts; // key name, "when key pressed" scripts
123124
std::vector<std::string> m_extensions;
124125
std::vector<std::shared_ptr<VirtualMachine>> m_runningScripts;
125126
std::vector<VirtualMachine *> m_scriptsToRemove;

test/blocks/event_blocks_test.cpp

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,13 +92,15 @@ TEST_F(EventBlocksTest, RegisterBlocks)
9292
EXPECT_CALL(m_engineMock, addCompileFunction(m_section.get(), "event_broadcastandwait", &EventBlocks::compileBroadcastAndWait));
9393
EXPECT_CALL(m_engineMock, addCompileFunction(m_section.get(), "event_whenbroadcastreceived", &EventBlocks::compileWhenBroadcastReceived));
9494
EXPECT_CALL(m_engineMock, addCompileFunction(m_section.get(), "event_whenbackdropswitchesto", &EventBlocks::compileWhenBackdropSwitchesTo));
95+
EXPECT_CALL(m_engineMock, addCompileFunction(m_section.get(), "event_whenkeypressed", &EventBlocks::compileWhenKeyPressed));
9596

9697
// Inputs
9798
EXPECT_CALL(m_engineMock, addInput(m_section.get(), "BROADCAST_INPUT", EventBlocks::BROADCAST_INPUT)).Times(1);
9899

99100
// Fields
100101
EXPECT_CALL(m_engineMock, addField(m_section.get(), "BROADCAST_OPTION", EventBlocks::BROADCAST_OPTION));
101102
EXPECT_CALL(m_engineMock, addField(m_section.get(), "BACKDROP", EventBlocks::BACKDROP));
103+
EXPECT_CALL(m_engineMock, addField(m_section.get(), "KEY_OPTION", EventBlocks::KEY_OPTION));
102104

103105
m_section->registerBlocks(&m_engineMock);
104106
}
@@ -271,3 +273,33 @@ TEST_F(EventBlocksTest, WhenBackdropSwitchesTo)
271273
ASSERT_TRUE(compiler.variables().empty());
272274
ASSERT_TRUE(compiler.lists().empty());
273275
}
276+
277+
TEST_F(EventBlocksTest, WhenKeyPressed)
278+
{
279+
Compiler compiler(&m_engineMock);
280+
281+
// when key "a" pressed
282+
auto block1 = createEventBlock("a", "event_whenkeypressed");
283+
addValueField(block1, "KEY_OPTION", EventBlocks::KEY_OPTION, "a");
284+
285+
// when key "left arrow" pressed
286+
auto block2 = createEventBlock("b", "event_whenkeypressed");
287+
addValueField(block2, "KEY_OPTION", EventBlocks::KEY_OPTION, "left arrow");
288+
289+
compiler.init();
290+
291+
EXPECT_CALL(m_engineMock, addKeyPressScript(block1, "a"));
292+
compiler.setBlock(block1);
293+
EventBlocks::compileWhenKeyPressed(&compiler);
294+
295+
EXPECT_CALL(m_engineMock, addKeyPressScript(block2, "left arrow"));
296+
compiler.setBlock(block2);
297+
EventBlocks::compileWhenKeyPressed(&compiler);
298+
299+
compiler.end();
300+
301+
ASSERT_EQ(compiler.bytecode(), std::vector<unsigned int>({ vm::OP_START, vm::OP_HALT }));
302+
ASSERT_TRUE(compiler.constValues().empty());
303+
ASSERT_TRUE(compiler.variables().empty());
304+
ASSERT_TRUE(compiler.lists().empty());
305+
}

test/mocks/enginemock.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,8 +69,8 @@ class EngineMock : public IEngine
6969
MOCK_METHOD(int, findBroadcastById, (const std::string &), (const, override));
7070

7171
MOCK_METHOD(void, addBroadcastScript, (std::shared_ptr<Block>, Broadcast *), (override));
72-
7372
MOCK_METHOD(void, addCloneInitScript, (std::shared_ptr<Block>), (override));
73+
MOCK_METHOD(void, addKeyPressScript, (std::shared_ptr<Block>, std::string), (override));
7474

7575
MOCK_METHOD(const std::vector<std::shared_ptr<Target>> &, targets, (), (const, override));
7676
MOCK_METHOD(void, setTargets, (const std::vector<std::shared_ptr<Target>> &), (override));

0 commit comments

Comments
 (0)