Skip to content

Commit fd1e9a1

Browse files
committed
Add KeyEvent class
1 parent 9b33a2a commit fd1e9a1

File tree

8 files changed

+431
-0
lines changed

8 files changed

+431
-0
lines changed

CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ target_sources(scratchcpp
4747
include/scratchcpp/stage.h
4848
include/scratchcpp/sprite.h
4949
include/scratchcpp/itimer.h
50+
include/scratchcpp/keyevent.h
5051
)
5152

5253
add_library(zip SHARED

include/scratchcpp/keyevent.h

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
// SPDX-License-Identifier: Apache-2.0
2+
3+
#pragma once
4+
5+
#include "global.h"
6+
#include "spimpl.h"
7+
8+
namespace libscratchcpp
9+
{
10+
11+
class KeyEventPrivate;
12+
13+
class LIBSCRATCHCPP_EXPORT KeyEvent
14+
{
15+
public:
16+
enum class Type
17+
{
18+
Any,
19+
Space,
20+
Left,
21+
Up,
22+
Right,
23+
Down,
24+
Enter
25+
};
26+
27+
KeyEvent(Type type = Type::Any);
28+
KeyEvent(const std::string &name);
29+
30+
Type type() const;
31+
const std::string &name() const;
32+
33+
private:
34+
spimpl::impl_ptr<KeyEventPrivate> impl;
35+
};
36+
37+
} // namespace libscratchcpp

src/scratch/CMakeLists.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,4 +45,7 @@ target_sources(scratchcpp
4545
entity.cpp
4646
entity_p.cpp
4747
entity_p.h
48+
keyevent.cpp
49+
keyevent_p.cpp
50+
keyevent_p.h
4851
)

src/scratch/keyevent.cpp

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// SPDX-License-Identifier: Apache-2.0
2+
3+
#include <scratchcpp/keyevent.h>
4+
5+
#include "keyevent_p.h"
6+
7+
namespace libscratchcpp
8+
{
9+
10+
/*! Constructs KeyEvent. */
11+
KeyEvent::KeyEvent(Type type) :
12+
impl(spimpl::make_impl<KeyEventPrivate>(type))
13+
{
14+
}
15+
16+
/*! Constructs KeyEvent from a key name. */
17+
KeyEvent::KeyEvent(const std::string &name) :
18+
impl(spimpl::make_impl<KeyEventPrivate>(name))
19+
{
20+
}
21+
22+
/*! Returns the type of the key. */
23+
KeyEvent::Type KeyEvent::type() const
24+
{
25+
return impl->type;
26+
}
27+
28+
/*! Returns the name of the key. */
29+
const std::string &KeyEvent::name() const
30+
{
31+
return impl->name;
32+
}
33+
34+
} // namespace libscratchcpp

src/scratch/keyevent_p.cpp

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
// SPDX-License-Identifier: Apache-2.0
2+
3+
#include <unordered_map>
4+
#include <algorithm>
5+
6+
#include "keyevent_p.h"
7+
8+
namespace libscratchcpp
9+
{
10+
11+
static std::unordered_map<KeyEvent::Type, std::string> KEY_NAME = {
12+
{ KeyEvent::Type::Space, "space" }, { KeyEvent::Type::Left, "left arrow" }, { KeyEvent::Type::Up, "up arrow" },
13+
{ KeyEvent::Type::Right, "right arrow" }, { KeyEvent::Type::Down, "down arrow" }, { KeyEvent::Type::Enter, "enter" }
14+
};
15+
16+
KeyEventPrivate::KeyEventPrivate(KeyEvent::Type type) :
17+
type(type)
18+
{
19+
auto it = KEY_NAME.find(type);
20+
21+
if (it == KEY_NAME.cend())
22+
this->type = KeyEvent::Type::Any;
23+
else
24+
name = it->second;
25+
}
26+
27+
KeyEventPrivate::KeyEventPrivate(const std::string &name) :
28+
name(name)
29+
{
30+
// See https://github.com/scratchfoundation/scratch-vm/blob/2a00145b8a968b04f278808858f79fa6d6e79946/src/io/keyboard.js#L93
31+
32+
// Convert from ASCII if a number was dropped in
33+
try {
34+
double numberDouble = std::stod(name);
35+
long number = static_cast<long>(numberDouble);
36+
37+
if (numberDouble == number) {
38+
39+
if (number >= 48 && number <= 90) {
40+
this->name = static_cast<char>(number);
41+
convertNameToLowercase();
42+
43+
return;
44+
}
45+
46+
switch (number) {
47+
case 32:
48+
type = KeyEvent::Type::Space;
49+
break;
50+
51+
case 37:
52+
type = KeyEvent::Type::Left;
53+
break;
54+
55+
case 38:
56+
type = KeyEvent::Type::Up;
57+
break;
58+
59+
case 39:
60+
type = KeyEvent::Type::Right;
61+
break;
62+
63+
case 40:
64+
type = KeyEvent::Type::Down;
65+
break;
66+
67+
default:
68+
break;
69+
}
70+
71+
if (type != KeyEvent::Type::Any) {
72+
this->name = KEY_NAME[type];
73+
return;
74+
}
75+
}
76+
} catch (...) {
77+
}
78+
79+
// Check for a special key
80+
for (const auto &[key, value] : KEY_NAME) {
81+
if (value == name) {
82+
type = key;
83+
return;
84+
}
85+
}
86+
87+
// Use only the first character
88+
if (this->name.size() > 1)
89+
this->name = this->name[0];
90+
91+
// Check for the space character
92+
if (this->name == " ") {
93+
type = KeyEvent::Type::Space;
94+
this->name = KEY_NAME[type];
95+
}
96+
97+
convertNameToLowercase();
98+
}
99+
100+
void KeyEventPrivate::convertNameToLowercase()
101+
{
102+
std::transform(this->name.begin(), this->name.end(), this->name.begin(), ::tolower);
103+
}
104+
105+
} // namespace libscratchcpp

src/scratch/keyevent_p.h

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// SPDX-License-Identifier: Apache-2.0
2+
3+
#pragma once
4+
5+
#include <scratchcpp/keyevent.h>
6+
#include <string>
7+
8+
namespace libscratchcpp
9+
{
10+
11+
struct KeyEventPrivate
12+
{
13+
KeyEventPrivate(KeyEvent::Type type);
14+
KeyEventPrivate(const std::string &name);
15+
16+
void convertNameToLowercase();
17+
18+
KeyEvent::Type type = KeyEvent::Type::Any;
19+
std::string name;
20+
};
21+
22+
} // namespace libscratchcpp

test/scratch_classes/CMakeLists.txt

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,3 +187,17 @@ target_link_libraries(
187187
)
188188

189189
gtest_discover_tests(variable_test)
190+
191+
# keyevent_test
192+
add_executable(
193+
keyevent_test
194+
keyevent_test.cpp
195+
)
196+
197+
target_link_libraries(
198+
keyevent_test
199+
GTest::gtest_main
200+
scratchcpp
201+
)
202+
203+
gtest_discover_tests(keyevent_test)

0 commit comments

Comments
 (0)