gosu 0.7.10.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/COPYING.txt +29 -0
- data/Gosu/Async.hpp +48 -0
- data/Gosu/Audio.hpp +145 -0
- data/Gosu/AutoLink.hpp +16 -0
- data/Gosu/Bitmap.hpp +85 -0
- data/Gosu/ButtonsMac.hpp +114 -0
- data/Gosu/ButtonsWin.hpp +111 -0
- data/Gosu/ButtonsX.hpp +115 -0
- data/Gosu/Color.hpp +172 -0
- data/Gosu/Directories.hpp +36 -0
- data/Gosu/Font.hpp +59 -0
- data/Gosu/Fwd.hpp +31 -0
- data/Gosu/Gosu.hpp +26 -0
- data/Gosu/Graphics.hpp +86 -0
- data/Gosu/GraphicsBase.hpp +45 -0
- data/Gosu/IO.hpp +255 -0
- data/Gosu/Image.hpp +148 -0
- data/Gosu/ImageData.hpp +45 -0
- data/Gosu/Input.hpp +116 -0
- data/Gosu/Math.hpp +95 -0
- data/Gosu/Platform.hpp +61 -0
- data/Gosu/RotFlip.hpp +116 -0
- data/Gosu/Sockets.hpp +129 -0
- data/Gosu/Text.hpp +47 -0
- data/Gosu/TextInput.hpp +57 -0
- data/Gosu/Timing.hpp +16 -0
- data/Gosu/Utility.hpp +24 -0
- data/Gosu/WinUtility.hpp +76 -0
- data/Gosu/Window.hpp +84 -0
- data/GosuImpl/Async.cpp +37 -0
- data/GosuImpl/AudioFmod.cpp +417 -0
- data/GosuImpl/AudioSDL.cpp +255 -0
- data/GosuImpl/DirectoriesMac.mm +38 -0
- data/GosuImpl/DirectoriesUnix.cpp +48 -0
- data/GosuImpl/DirectoriesWin.cpp +42 -0
- data/GosuImpl/FileUnix.cpp +100 -0
- data/GosuImpl/FileWin.cpp +83 -0
- data/GosuImpl/Graphics/Bitmap.cpp +116 -0
- data/GosuImpl/Graphics/BitmapBMP.cpp +232 -0
- data/GosuImpl/Graphics/BitmapColorKey.cpp +39 -0
- data/GosuImpl/Graphics/BitmapPNG.cpp +276 -0
- data/GosuImpl/Graphics/BitmapUtils.cpp +67 -0
- data/GosuImpl/Graphics/BlockAllocator.cpp +127 -0
- data/GosuImpl/Graphics/BlockAllocator.hpp +34 -0
- data/GosuImpl/Graphics/Color.cpp +126 -0
- data/GosuImpl/Graphics/Common.hpp +21 -0
- data/GosuImpl/Graphics/DrawOp.hpp +154 -0
- data/GosuImpl/Graphics/Font.cpp +110 -0
- data/GosuImpl/Graphics/Graphics.cpp +295 -0
- data/GosuImpl/Graphics/Image.cpp +159 -0
- data/GosuImpl/Graphics/LargeImageData.cpp +115 -0
- data/GosuImpl/Graphics/LargeImageData.hpp +37 -0
- data/GosuImpl/Graphics/RotFlip.cpp +184 -0
- data/GosuImpl/Graphics/TexChunk.cpp +77 -0
- data/GosuImpl/Graphics/TexChunk.hpp +40 -0
- data/GosuImpl/Graphics/Text.cpp +223 -0
- data/GosuImpl/Graphics/TextMac.cpp +242 -0
- data/GosuImpl/Graphics/TextPangoFT.cpp +186 -0
- data/GosuImpl/Graphics/TextWin.cpp +172 -0
- data/GosuImpl/Graphics/Texture.cpp +104 -0
- data/GosuImpl/Graphics/Texture.hpp +34 -0
- data/GosuImpl/IO.cpp +48 -0
- data/GosuImpl/InputMac.mm +677 -0
- data/GosuImpl/InputWin.cpp +444 -0
- data/GosuImpl/InputX.cpp +158 -0
- data/GosuImpl/MacUtility.hpp +48 -0
- data/GosuImpl/Math.cpp +49 -0
- data/GosuImpl/RubyGosu.swg +474 -0
- data/GosuImpl/RubyGosuStub.mm +17 -0
- data/GosuImpl/RubyGosu_DllMain.cxx +30 -0
- data/GosuImpl/RubyGosu_wrap.cxx +8521 -0
- data/GosuImpl/RubyGosu_wrap.h +31 -0
- data/GosuImpl/Sockets/CommSocket.cpp +304 -0
- data/GosuImpl/Sockets/ListenerSocket.cpp +60 -0
- data/GosuImpl/Sockets/MessageSocket.cpp +136 -0
- data/GosuImpl/Sockets/Socket.cpp +145 -0
- data/GosuImpl/Sockets/Sockets.hpp +66 -0
- data/GosuImpl/TextInputMac.mm +207 -0
- data/GosuImpl/TextInputWin.cpp +197 -0
- data/GosuImpl/TextInputX.cpp +201 -0
- data/GosuImpl/TextTTFWin.cpp +247 -0
- data/GosuImpl/TimingUnix.cpp +17 -0
- data/GosuImpl/TimingWin.cpp +28 -0
- data/GosuImpl/Utility.cpp +140 -0
- data/GosuImpl/WinMain.cpp +69 -0
- data/GosuImpl/WinUtility.cpp +137 -0
- data/GosuImpl/WindowMac.mm +466 -0
- data/GosuImpl/WindowWin.cpp +447 -0
- data/GosuImpl/WindowX.cpp +392 -0
- data/GosuImpl/X11vroot.h +118 -0
- data/README.txt +13 -0
- data/Rakefile +178 -0
- data/examples/ChipmunkIntegration.rb +275 -0
- data/examples/CptnRuby.rb +231 -0
- data/examples/MoreChipmunkAndRMagick.rb +155 -0
- data/examples/OpenGLIntegration.rb +232 -0
- data/examples/RMagickIntegration.rb +449 -0
- data/examples/TextInput.cpp +170 -0
- data/examples/TextInput.rb +139 -0
- data/examples/Tutorial.cpp +215 -0
- data/examples/Tutorial.rb +137 -0
- data/examples/media/Beep.wav +0 -0
- data/examples/media/CptnRuby Gem.png +0 -0
- data/examples/media/CptnRuby Map.txt +25 -0
- data/examples/media/CptnRuby Tileset.png +0 -0
- data/examples/media/CptnRuby.png +0 -0
- data/examples/media/Cursor.png +0 -0
- data/examples/media/Earth.png +0 -0
- data/examples/media/Explosion.wav +0 -0
- data/examples/media/LargeStar.png +0 -0
- data/examples/media/Sky.jpg +0 -0
- data/examples/media/Smoke.png +0 -0
- data/examples/media/Soldier.png +0 -0
- data/examples/media/Space.png +0 -0
- data/examples/media/Star.png +0 -0
- data/examples/media/Starfighter.bmp +0 -0
- data/linux/Makefile.in +98 -0
- data/linux/configure +5658 -0
- data/linux/configure.ac +126 -0
- data/linux/extconf.rb +11 -0
- data/mac/English.lproj/InfoPlist.strings +0 -0
- data/mac/Gosu-Info.plist +26 -0
- data/mac/Gosu.xcodeproj/project.pbxproj +1194 -0
- data/mac/RubyGosu Template-Info.plist +26 -0
- data/mac/libboost_thread_1_34_1_universal.a +0 -0
- data/mac/libboost_thread_d_1_34_1_universal.a +0 -0
- data/mac/libfmod_universal.a +0 -0
- data/mac/libpng_universal.a +0 -0
- data/mac/libz_universal.a +0 -0
- data/reference/Async_8hpp-source.html +70 -0
- data/reference/Audio_8hpp-source.html +114 -0
- data/reference/Audio_8hpp.html +50 -0
- data/reference/AutoLink_8hpp-source.html +38 -0
- data/reference/AutoLink_8hpp.html +34 -0
- data/reference/Bitmap_8hpp-source.html +85 -0
- data/reference/Bitmap_8hpp.html +58 -0
- data/reference/ButtonsMac_8hpp-source.html +133 -0
- data/reference/ButtonsWin_8hpp-source.html +133 -0
- data/reference/ButtonsX_8hpp-source.html +134 -0
- data/reference/Color_8hpp-source.html +169 -0
- data/reference/Color_8hpp.html +85 -0
- data/reference/Directories_8hpp-source.html +42 -0
- data/reference/Directories_8hpp.html +46 -0
- data/reference/Font_8hpp-source.html +65 -0
- data/reference/Font_8hpp.html +41 -0
- data/reference/Fwd_8hpp-source.html +52 -0
- data/reference/Fwd_8hpp.html +37 -0
- data/reference/Gosu_8hpp-source.html +48 -0
- data/reference/Gosu_8hpp.html +34 -0
- data/reference/GraphicsBase_8hpp-source.html +57 -0
- data/reference/GraphicsBase_8hpp.html +56 -0
- data/reference/Graphics_8hpp-source.html +96 -0
- data/reference/Graphics_8hpp.html +53 -0
- data/reference/IO_8hpp-source.html +255 -0
- data/reference/IO_8hpp.html +74 -0
- data/reference/ImageData_8hpp-source.html +62 -0
- data/reference/ImageData_8hpp.html +43 -0
- data/reference/Image_8hpp-source.html +126 -0
- data/reference/Image_8hpp.html +48 -0
- data/reference/Input_8hpp-source.html +118 -0
- data/reference/Input_8hpp.html +50 -0
- data/reference/Math_8hpp-source.html +92 -0
- data/reference/Math_8hpp.html +74 -0
- data/reference/Platform_8hpp-source.html +83 -0
- data/reference/Platform_8hpp.html +73 -0
- data/reference/RotFlip_8hpp-source.html +138 -0
- data/reference/RotFlip_8hpp.html +77 -0
- data/reference/Sockets_8hpp-source.html +130 -0
- data/reference/Sockets_8hpp.html +66 -0
- data/reference/TextInput_8hpp-source.html +64 -0
- data/reference/TextInput_8hpp.html +41 -0
- data/reference/Text_8hpp-source.html +51 -0
- data/reference/Text_8hpp.html +46 -0
- data/reference/Timing_8hpp-source.html +36 -0
- data/reference/Timing_8hpp.html +42 -0
- data/reference/Utility_8hpp-source.html +44 -0
- data/reference/Utility_8hpp.html +48 -0
- data/reference/WinUtility_8hpp-source.html +79 -0
- data/reference/WinUtility_8hpp.html +64 -0
- data/reference/Window_8hpp-source.html +91 -0
- data/reference/Window_8hpp.html +41 -0
- data/reference/annotated.html +51 -0
- data/reference/classGosu_1_1Audio-members.html +34 -0
- data/reference/classGosu_1_1Audio.html +46 -0
- data/reference/classGosu_1_1Bitmap-members.html +44 -0
- data/reference/classGosu_1_1Bitmap.html +263 -0
- data/reference/classGosu_1_1Buffer-members.html +44 -0
- data/reference/classGosu_1_1Buffer.html +78 -0
- data/reference/classGosu_1_1Buffer.png +0 -0
- data/reference/classGosu_1_1Button-members.html +36 -0
- data/reference/classGosu_1_1Button.html +143 -0
- data/reference/classGosu_1_1Color-members.html +56 -0
- data/reference/classGosu_1_1Color.html +387 -0
- data/reference/classGosu_1_1File-members.html +41 -0
- data/reference/classGosu_1_1File.html +69 -0
- data/reference/classGosu_1_1File.png +0 -0
- data/reference/classGosu_1_1Font-members.html +39 -0
- data/reference/classGosu_1_1Font.html +309 -0
- data/reference/classGosu_1_1Graphics-members.html +50 -0
- data/reference/classGosu_1_1Graphics.html +234 -0
- data/reference/classGosu_1_1Image-members.html +45 -0
- data/reference/classGosu_1_1Image.html +518 -0
- data/reference/classGosu_1_1ImageData-members.html +37 -0
- data/reference/classGosu_1_1ImageData.html +60 -0
- data/reference/classGosu_1_1Input-members.html +44 -0
- data/reference/classGosu_1_1Input.html +223 -0
- data/reference/classGosu_1_1MessageSocket-members.html +40 -0
- data/reference/classGosu_1_1MessageSocket.html +233 -0
- data/reference/classGosu_1_1Resource-members.html +39 -0
- data/reference/classGosu_1_1Resource.html +116 -0
- data/reference/classGosu_1_1Resource.png +0 -0
- data/reference/classGosu_1_1Sample-members.html +37 -0
- data/reference/classGosu_1_1Sample.html +200 -0
- data/reference/classGosu_1_1SampleInstance-members.html +38 -0
- data/reference/classGosu_1_1SampleInstance.html +169 -0
- data/reference/classGosu_1_1Song-members.html +43 -0
- data/reference/classGosu_1_1Song.html +260 -0
- data/reference/classGosu_1_1TextInput-members.html +38 -0
- data/reference/classGosu_1_1TextInput.html +121 -0
- data/reference/classGosu_1_1Window-members.html +50 -0
- data/reference/classGosu_1_1Window.html +271 -0
- data/reference/doxyfile +233 -0
- data/reference/doxygen.css +433 -0
- data/reference/doxygen.png +0 -0
- data/reference/files.html +54 -0
- data/reference/functions.html +236 -0
- data/reference/functions_enum.html +45 -0
- data/reference/functions_func.html +227 -0
- data/reference/functions_vars.html +47 -0
- data/reference/hierarchy.html +53 -0
- data/reference/index.html +26 -0
- data/reference/namespaceGosu.html +2890 -0
- data/reference/namespaceGosu_1_1Colors.html +70 -0
- data/reference/namespaceGosu_1_1Win.html +275 -0
- data/reference/namespacemembers.html +216 -0
- data/reference/namespacemembers_enum.html +52 -0
- data/reference/namespacemembers_eval.html +54 -0
- data/reference/namespacemembers_func.html +185 -0
- data/reference/namespacemembers_type.html +46 -0
- data/reference/namespacemembers_vars.html +46 -0
- data/reference/namespaces.html +35 -0
- data/reference/tab_b.gif +0 -0
- data/reference/tab_l.gif +0 -0
- data/reference/tab_r.gif +0 -0
- data/reference/tabs.css +102 -0
- data/windows/Gosu.sln +29 -0
- data/windows/Gosu.vcproj +553 -0
- data/windows/RubyGosu.vcproj +138 -0
- metadata +305 -0
@@ -0,0 +1,34 @@
|
|
1
|
+
#ifndef GOSUIMPL_GRAPHICS_TEXTURE_HPP
|
2
|
+
#define GOSUIMPL_GRAPHICS_TEXTURE_HPP
|
3
|
+
|
4
|
+
#include <Gosu/Fwd.hpp>
|
5
|
+
#include <GosuImpl/Graphics/Common.hpp>
|
6
|
+
#include <GosuImpl/Graphics/TexChunk.hpp>
|
7
|
+
#include <GosuImpl/Graphics/BlockAllocator.hpp>
|
8
|
+
#include <boost/cstdint.hpp>
|
9
|
+
#include <boost/shared_ptr.hpp>
|
10
|
+
#include <vector>
|
11
|
+
|
12
|
+
namespace Gosu
|
13
|
+
{
|
14
|
+
class Texture
|
15
|
+
{
|
16
|
+
BlockAllocator allocator;
|
17
|
+
GLuint name;
|
18
|
+
unsigned num;
|
19
|
+
|
20
|
+
public:
|
21
|
+
static unsigned maxTextureSize();
|
22
|
+
|
23
|
+
Texture(unsigned size);
|
24
|
+
~Texture();
|
25
|
+
unsigned size() const;
|
26
|
+
GLuint texName() const;
|
27
|
+
std::auto_ptr<TexChunk>
|
28
|
+
tryAlloc(Graphics& graphics, DrawOpQueue& queue, boost::shared_ptr<Texture> ptr, const Bitmap& bmp,
|
29
|
+
unsigned srcX, unsigned srcY, unsigned srcWidth, unsigned srcHeight, unsigned padding);
|
30
|
+
void free(unsigned x, unsigned y);
|
31
|
+
};
|
32
|
+
}
|
33
|
+
|
34
|
+
#endif
|
data/GosuImpl/IO.cpp
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
#include <Gosu/IO.hpp>
|
2
|
+
#include <cassert>
|
3
|
+
#include <cstring>
|
4
|
+
|
5
|
+
void Gosu::Reader::read(void* dest, std::size_t length)
|
6
|
+
{
|
7
|
+
res->read(pos, length, dest);
|
8
|
+
seek(length);
|
9
|
+
}
|
10
|
+
|
11
|
+
void Gosu::Writer::write(const void* source, std::size_t length)
|
12
|
+
{
|
13
|
+
// Try to resize the source if necessary.
|
14
|
+
if (pos + length > res->size())
|
15
|
+
res->resize(pos + length);
|
16
|
+
|
17
|
+
res->write(pos, length, source);
|
18
|
+
seek(length);
|
19
|
+
}
|
20
|
+
|
21
|
+
void Gosu::Buffer::read(std::size_t offset, std::size_t length,
|
22
|
+
void* destBuffer) const
|
23
|
+
{
|
24
|
+
assert(offset + length <= size());
|
25
|
+
if (length)
|
26
|
+
std::memcpy(destBuffer, &buf[offset], length);
|
27
|
+
}
|
28
|
+
|
29
|
+
void Gosu::Buffer::write(std::size_t offset, std::size_t length,
|
30
|
+
const void* sourceBuffer)
|
31
|
+
{
|
32
|
+
assert(offset + length <= size());
|
33
|
+
if (length)
|
34
|
+
std::memcpy(&buf[offset], sourceBuffer, length);
|
35
|
+
}
|
36
|
+
|
37
|
+
void Gosu::loadFile(Buffer& buffer, const std::wstring& filename)
|
38
|
+
{
|
39
|
+
File file(filename);
|
40
|
+
buffer.resize(file.size());
|
41
|
+
file.read(0, buffer.size(), buffer.data());
|
42
|
+
}
|
43
|
+
|
44
|
+
void Gosu::saveFile(const Buffer& buffer, const std::wstring& filename)
|
45
|
+
{
|
46
|
+
File file(filename, fmReplace);
|
47
|
+
file.write(0, buffer.size(), buffer.data());
|
48
|
+
}
|
@@ -0,0 +1,677 @@
|
|
1
|
+
#import <AppKit/AppKit.h>
|
2
|
+
#import <Carbon/Carbon.h>
|
3
|
+
#include <Gosu/Input.hpp>
|
4
|
+
#include <Gosu/TextInput.hpp>
|
5
|
+
#include <Gosu/Utility.hpp>
|
6
|
+
#include <IOKit/hidsystem/IOLLEvent.h>
|
7
|
+
#include <boost/array.hpp>
|
8
|
+
#include <boost/cstdint.hpp>
|
9
|
+
#include <map>
|
10
|
+
#include <string>
|
11
|
+
#include <vector>
|
12
|
+
|
13
|
+
#include <mach/mach.h>
|
14
|
+
#include <mach/mach_error.h>
|
15
|
+
#include <Kernel/IOKit/hidsystem/IOHIDUsageTables.h>
|
16
|
+
#include <CoreFoundation/CoreFoundation.h>
|
17
|
+
#include <IOKit/hid/IOHIDLib.h>
|
18
|
+
#include <IOKit/hid/IOHIDKeys.h>
|
19
|
+
#include <IOKit/IOKitLib.h>
|
20
|
+
#include <IOKit/IOCFPlugIn.h>
|
21
|
+
#include <stdexcept>
|
22
|
+
#include <vector>
|
23
|
+
#include <boost/utility.hpp>
|
24
|
+
#include <boost/shared_ptr.hpp>
|
25
|
+
|
26
|
+
// USB Gamepad code, likely to be moved somewhere else later.
|
27
|
+
// This is Frankencode until the Input redesign happens.
|
28
|
+
namespace {
|
29
|
+
using namespace std;
|
30
|
+
using namespace Gosu;
|
31
|
+
using boost::shared_ptr;
|
32
|
+
|
33
|
+
class CFScope : boost::noncopyable
|
34
|
+
{
|
35
|
+
CFTypeRef ref;
|
36
|
+
public:
|
37
|
+
CFScope(CFTypeRef ref) : ref(ref) {}
|
38
|
+
~CFScope() { CFRelease(ref); }
|
39
|
+
};
|
40
|
+
|
41
|
+
class IOScope : boost::noncopyable
|
42
|
+
{
|
43
|
+
io_object_t ref;
|
44
|
+
public:
|
45
|
+
IOScope(io_object_t ref) : ref(ref) {}
|
46
|
+
~IOScope() { IOObjectRelease(ref); }
|
47
|
+
};
|
48
|
+
|
49
|
+
template<typename Negatable>
|
50
|
+
void checkTrue(Negatable cond, const char* message = "work")
|
51
|
+
{
|
52
|
+
if (!cond)
|
53
|
+
throw runtime_error(string("HID system failed to ") + message);
|
54
|
+
}
|
55
|
+
|
56
|
+
void checkIO(IOReturn val, const char* message = "work")
|
57
|
+
{
|
58
|
+
checkTrue(val == kIOReturnSuccess, message);
|
59
|
+
}
|
60
|
+
|
61
|
+
string getDictString(CFMutableDictionaryRef dict, CFStringRef key, const char* what)
|
62
|
+
{
|
63
|
+
char buf[256];
|
64
|
+
CFStringRef str =
|
65
|
+
(CFStringRef)CFDictionaryGetValue(dict, key);
|
66
|
+
checkTrue(str && CFStringGetCString(str, buf, sizeof buf, CFStringGetSystemEncoding()),
|
67
|
+
what);
|
68
|
+
return buf;
|
69
|
+
}
|
70
|
+
|
71
|
+
SInt32 getDictSInt32(CFMutableDictionaryRef dict, CFStringRef key, const char* what)
|
72
|
+
{
|
73
|
+
SInt32 value;
|
74
|
+
CFNumberRef number =
|
75
|
+
(CFNumberRef)CFDictionaryGetValue(dict, key);
|
76
|
+
checkTrue(number && CFNumberGetValue(number, kCFNumberSInt32Type, &value),
|
77
|
+
what);
|
78
|
+
return value;
|
79
|
+
}
|
80
|
+
|
81
|
+
struct Axis
|
82
|
+
{
|
83
|
+
IOHIDElementCookie cookie;
|
84
|
+
long min, max;
|
85
|
+
enum Role { mainX, mainY } role;
|
86
|
+
|
87
|
+
// Some devices report more axis than they have, with random constant values.
|
88
|
+
// An axis has to go into, and out of the neutral zone so it will be reported.
|
89
|
+
bool wasNeutralOnce;
|
90
|
+
|
91
|
+
Axis(CFMutableDictionaryRef dict, Role role)
|
92
|
+
: role(role), wasNeutralOnce(false)
|
93
|
+
{
|
94
|
+
cookie = (IOHIDElementCookie)getDictSInt32(dict, CFSTR(kIOHIDElementCookieKey),
|
95
|
+
"get an element cookie");
|
96
|
+
min = getDictSInt32(dict, CFSTR(kIOHIDElementMinKey),
|
97
|
+
"get a min value");
|
98
|
+
max = getDictSInt32(dict, CFSTR(kIOHIDElementMaxKey),
|
99
|
+
"get a max value");
|
100
|
+
}
|
101
|
+
};
|
102
|
+
|
103
|
+
struct Hat
|
104
|
+
{
|
105
|
+
IOHIDElementCookie cookie;
|
106
|
+
enum { fourWay, eightWay, unknown } kind;
|
107
|
+
long min;
|
108
|
+
|
109
|
+
Hat(CFMutableDictionaryRef dict)
|
110
|
+
{
|
111
|
+
cookie = (IOHIDElementCookie)getDictSInt32(dict, CFSTR(kIOHIDElementCookieKey),
|
112
|
+
"an element cookie");
|
113
|
+
min = getDictSInt32(dict, CFSTR(kIOHIDElementMinKey),
|
114
|
+
"a min value");
|
115
|
+
SInt32 max = getDictSInt32(dict, CFSTR(kIOHIDElementMaxKey),
|
116
|
+
"a max value");
|
117
|
+
if ((max - min) == 3)
|
118
|
+
kind = fourWay;
|
119
|
+
else if ((max - min) == 7)
|
120
|
+
kind = eightWay;
|
121
|
+
else
|
122
|
+
kind = unknown;
|
123
|
+
}
|
124
|
+
};
|
125
|
+
|
126
|
+
struct Button
|
127
|
+
{
|
128
|
+
IOHIDElementCookie cookie;
|
129
|
+
|
130
|
+
Button(CFMutableDictionaryRef dict)
|
131
|
+
{
|
132
|
+
cookie = (IOHIDElementCookie)getDictSInt32(dict, CFSTR(kIOHIDElementCookieKey),
|
133
|
+
"element cookie");
|
134
|
+
}
|
135
|
+
};
|
136
|
+
|
137
|
+
struct Device
|
138
|
+
{
|
139
|
+
shared_ptr<IOHIDDeviceInterface*> interface;
|
140
|
+
|
141
|
+
std::string name;
|
142
|
+
vector<Axis> axis;
|
143
|
+
vector<Hat> hats;
|
144
|
+
vector<Button> buttons;
|
145
|
+
};
|
146
|
+
|
147
|
+
class System
|
148
|
+
{
|
149
|
+
vector<Device> devices;
|
150
|
+
|
151
|
+
static void closeAndReleaseInterface(IOHIDDeviceInterface** ptr)
|
152
|
+
{
|
153
|
+
(*ptr)->close(ptr); // Won't hurt if open() wasn't called
|
154
|
+
(*ptr)->Release(ptr);
|
155
|
+
}
|
156
|
+
|
157
|
+
static void eraseDevice(void* target, IOReturn, void* refcon, void*)
|
158
|
+
{
|
159
|
+
System& self = *static_cast<System*>(target);
|
160
|
+
for (unsigned i = 0; i < self.devices.size(); ++i)
|
161
|
+
if (self.devices[i].interface.get() == refcon)
|
162
|
+
{
|
163
|
+
self.devices.erase(self.devices.begin() + i);
|
164
|
+
return;
|
165
|
+
}
|
166
|
+
assert(false);
|
167
|
+
}
|
168
|
+
|
169
|
+
bool isDeviceInteresting(CFMutableDictionaryRef properties)
|
170
|
+
{
|
171
|
+
// Get usage page/usage.
|
172
|
+
SInt32 page = getDictSInt32(properties, CFSTR(kIOHIDPrimaryUsagePageKey),
|
173
|
+
"a usage page");
|
174
|
+
SInt32 usage = getDictSInt32(properties, CFSTR(kIOHIDPrimaryUsageKey),
|
175
|
+
"a usage value");
|
176
|
+
// Device uninteresting?
|
177
|
+
return page == kHIDPage_GenericDesktop &&
|
178
|
+
(usage == kHIDUsage_GD_Joystick ||
|
179
|
+
usage == kHIDUsage_GD_GamePad ||
|
180
|
+
usage == kHIDUsage_GD_MultiAxisController);
|
181
|
+
}
|
182
|
+
|
183
|
+
shared_ptr<IOHIDDeviceInterface*> getDeviceInterface(io_registry_entry_t object)
|
184
|
+
{
|
185
|
+
IOCFPlugInInterface** intermediate = 0;
|
186
|
+
SInt32 theScore;
|
187
|
+
checkIO(IOCreatePlugInInterfaceForService(object, kIOHIDDeviceUserClientTypeID,
|
188
|
+
kIOCFPlugInInterfaceID, &intermediate, &theScore),
|
189
|
+
"get intermediate device interface");
|
190
|
+
|
191
|
+
IOHIDDeviceInterface** rawResult = 0;
|
192
|
+
HRESULT ret = (*intermediate)->QueryInterface(intermediate,
|
193
|
+
CFUUIDGetUUIDBytes(kIOHIDDeviceInterfaceID),
|
194
|
+
reinterpret_cast<void**>(&rawResult));
|
195
|
+
(*intermediate)->Release(intermediate);
|
196
|
+
if (ret != S_OK)
|
197
|
+
checkTrue(false, "get real device interface through intermediate");
|
198
|
+
|
199
|
+
// Yay - got it safe in here.
|
200
|
+
shared_ptr<IOHIDDeviceInterface*> result(rawResult, closeAndReleaseInterface);
|
201
|
+
|
202
|
+
checkIO((*result)->open(result.get(), 0));
|
203
|
+
checkIO((*result)->setRemovalCallback(result.get(), eraseDevice, result.get(), this));
|
204
|
+
|
205
|
+
return result;
|
206
|
+
}
|
207
|
+
|
208
|
+
static void addElement(const void* value, void* parameter)
|
209
|
+
{
|
210
|
+
CFMutableDictionaryRef dict = (CFMutableDictionaryRef)value;
|
211
|
+
Device& target = *static_cast<Device*>(parameter);
|
212
|
+
|
213
|
+
SInt32 elementType = getDictSInt32(dict, CFSTR(kIOHIDElementTypeKey),
|
214
|
+
("an element type on " + target.name).c_str());
|
215
|
+
SInt32 usagePage = getDictSInt32(dict, CFSTR(kIOHIDElementUsagePageKey),
|
216
|
+
("an element page on " + target.name).c_str());
|
217
|
+
SInt32 usage = getDictSInt32(dict, CFSTR(kIOHIDElementUsageKey),
|
218
|
+
("an element usage on " + target.name).c_str());
|
219
|
+
|
220
|
+
if ((elementType == kIOHIDElementTypeInput_Misc) ||
|
221
|
+
(elementType == kIOHIDElementTypeInput_Button) ||
|
222
|
+
(elementType == kIOHIDElementTypeInput_Axis))
|
223
|
+
{
|
224
|
+
switch (usagePage)
|
225
|
+
{
|
226
|
+
case kHIDPage_GenericDesktop:
|
227
|
+
switch (usage)
|
228
|
+
{
|
229
|
+
case kHIDUsage_GD_Y:
|
230
|
+
case kHIDUsage_GD_Ry:
|
231
|
+
target.axis.push_back(Axis(dict, Axis::mainY));
|
232
|
+
break;
|
233
|
+
case kHIDUsage_GD_X:
|
234
|
+
case kHIDUsage_GD_Rx:
|
235
|
+
case kHIDUsage_GD_Z:
|
236
|
+
case kHIDUsage_GD_Rz:
|
237
|
+
case kHIDUsage_GD_Slider:
|
238
|
+
case kHIDUsage_GD_Dial:
|
239
|
+
case kHIDUsage_GD_Wheel:
|
240
|
+
target.axis.push_back(Axis(dict, Axis::mainX));
|
241
|
+
break;
|
242
|
+
case kHIDUsage_GD_Hatswitch:
|
243
|
+
target.hats.push_back(Hat(dict));
|
244
|
+
break;
|
245
|
+
}
|
246
|
+
break;
|
247
|
+
case kHIDPage_Button:
|
248
|
+
target.buttons.push_back(Button(dict));
|
249
|
+
break;
|
250
|
+
}
|
251
|
+
}
|
252
|
+
else if (elementType == kIOHIDElementTypeCollection)
|
253
|
+
addElementCollection(target, dict);
|
254
|
+
}
|
255
|
+
|
256
|
+
static void addElementCollection(Device& target, CFMutableDictionaryRef properties)
|
257
|
+
{
|
258
|
+
CFArrayRef array =
|
259
|
+
(CFArrayRef)CFDictionaryGetValue(properties, CFSTR(kIOHIDElementKey));
|
260
|
+
checkTrue(array,
|
261
|
+
("get an element list for " + target.name).c_str());
|
262
|
+
|
263
|
+
CFRange range = { 0, CFArrayGetCount(array) };
|
264
|
+
CFArrayApplyFunction(array, range, addElement, &target);
|
265
|
+
}
|
266
|
+
|
267
|
+
void addDevice(io_object_t object)
|
268
|
+
{
|
269
|
+
// Get handle to device properties.
|
270
|
+
CFMutableDictionaryRef properties;
|
271
|
+
IORegistryEntryCreateCFProperties(object, &properties,
|
272
|
+
kCFAllocatorDefault, kNilOptions);
|
273
|
+
if (!properties)
|
274
|
+
return;
|
275
|
+
CFScope guard(properties);
|
276
|
+
|
277
|
+
if (!isDeviceInteresting(properties))
|
278
|
+
return;
|
279
|
+
|
280
|
+
Device newDevice;
|
281
|
+
newDevice.interface = getDeviceInterface(object);
|
282
|
+
newDevice.name = getDictString(properties, CFSTR(kIOHIDProductKey),
|
283
|
+
"a product name");
|
284
|
+
addElementCollection(newDevice, properties);
|
285
|
+
devices.push_back(newDevice);
|
286
|
+
}
|
287
|
+
|
288
|
+
public:
|
289
|
+
System()
|
290
|
+
{
|
291
|
+
mach_port_t masterPort;
|
292
|
+
checkIO(IOMasterPort(bootstrap_port, &masterPort),
|
293
|
+
"get master port");
|
294
|
+
|
295
|
+
CFMutableDictionaryRef hidDeviceKey =
|
296
|
+
IOServiceMatching(kIOHIDDeviceKey);
|
297
|
+
checkTrue(hidDeviceKey,
|
298
|
+
"build device list");
|
299
|
+
|
300
|
+
io_iterator_t iterator;
|
301
|
+
checkIO(IOServiceGetMatchingServices(masterPort, hidDeviceKey, &iterator),
|
302
|
+
"set up HID iterator");
|
303
|
+
IOScope guard(iterator);
|
304
|
+
|
305
|
+
while (io_registry_entry_t deviceObject = IOIteratorNext(iterator))
|
306
|
+
{
|
307
|
+
IOScope guard(deviceObject);
|
308
|
+
addDevice(deviceObject);
|
309
|
+
}
|
310
|
+
}
|
311
|
+
|
312
|
+
unsigned countDevices() const
|
313
|
+
{
|
314
|
+
return devices.size();
|
315
|
+
}
|
316
|
+
|
317
|
+
const Device& getDevice(unsigned i) const
|
318
|
+
{
|
319
|
+
return devices.at(i);
|
320
|
+
}
|
321
|
+
|
322
|
+
boost::array<bool, gpNum> poll()
|
323
|
+
{
|
324
|
+
boost::array<bool, gpNum> result;
|
325
|
+
result.assign(false);
|
326
|
+
|
327
|
+
IOHIDEventStruct event;
|
328
|
+
for (int dev = 0; dev < devices.size(); ++dev)
|
329
|
+
{
|
330
|
+
// Axis
|
331
|
+
for (int ax = 0; ax < devices[dev].axis.size(); ++ax)
|
332
|
+
{
|
333
|
+
checkIO((*devices[dev].interface)->getElementValue(
|
334
|
+
devices[dev].interface.get(),
|
335
|
+
devices[dev].axis[ax].cookie, &event));
|
336
|
+
|
337
|
+
Axis& a = devices[dev].axis[ax];
|
338
|
+
if (event.value < (3 * a.min + 1 * a.max) / 4.0)
|
339
|
+
{
|
340
|
+
if (a.wasNeutralOnce)
|
341
|
+
result[(a.role == Axis::mainX ? gpLeft : gpUp) - gpRangeBegin] = true;
|
342
|
+
}
|
343
|
+
else if (event.value > (1 * a.min + 3 * a.max) / 4.0)
|
344
|
+
{
|
345
|
+
if (a.wasNeutralOnce)
|
346
|
+
result[(a.role == Axis::mainX ? gpRight : gpDown) - gpRangeBegin] = true;
|
347
|
+
}
|
348
|
+
else
|
349
|
+
a.wasNeutralOnce = true;
|
350
|
+
}
|
351
|
+
|
352
|
+
// Hats (merge into axis)
|
353
|
+
for (int hat = 0; hat < devices[dev].hats.size(); ++hat)
|
354
|
+
{
|
355
|
+
checkIO((*devices[dev].interface)->getElementValue(
|
356
|
+
devices[dev].interface.get(),
|
357
|
+
devices[dev].hats[hat].cookie, &event));
|
358
|
+
|
359
|
+
// In case device does not start at 0 as expected.
|
360
|
+
event.value -= devices[dev].hats[hat].min;
|
361
|
+
|
362
|
+
// Treat all hats as being 8-way.
|
363
|
+
if (devices[dev].hats[hat].kind == Hat::fourWay)
|
364
|
+
event.value *= 2;
|
365
|
+
|
366
|
+
switch (event.value)
|
367
|
+
{
|
368
|
+
// Must...resist...doing...crappy...fallthrough...magic...
|
369
|
+
case 0:
|
370
|
+
result[gpUp - gpRangeBegin] = true;
|
371
|
+
break;
|
372
|
+
case 1:
|
373
|
+
result[gpUp - gpRangeBegin] = true;
|
374
|
+
result[gpRight - gpRangeBegin] = true;
|
375
|
+
break;
|
376
|
+
case 2:
|
377
|
+
result[gpRight - gpRangeBegin] = true;
|
378
|
+
break;
|
379
|
+
case 3:
|
380
|
+
result[gpDown - gpRangeBegin] = true;
|
381
|
+
result[gpRight - gpRangeBegin] = true;
|
382
|
+
break;
|
383
|
+
case 4:
|
384
|
+
result[gpDown - gpRangeBegin] = true;
|
385
|
+
break;
|
386
|
+
case 5:
|
387
|
+
result[gpDown - gpRangeBegin] = true;
|
388
|
+
result[gpLeft - gpRangeBegin] = true;
|
389
|
+
break;
|
390
|
+
case 6:
|
391
|
+
result[gpLeft - gpRangeBegin] = true;
|
392
|
+
break;
|
393
|
+
case 7:
|
394
|
+
result[gpUp - gpRangeBegin] = true;
|
395
|
+
result[gpLeft - gpRangeBegin] = true;
|
396
|
+
break;
|
397
|
+
}
|
398
|
+
}
|
399
|
+
|
400
|
+
// Buttons
|
401
|
+
for (int btn = 0; btn < devices[dev].buttons.size() && btn < 16; ++btn)
|
402
|
+
{
|
403
|
+
checkIO((*devices[dev].interface)->getElementValue(
|
404
|
+
devices[dev].interface.get(),
|
405
|
+
devices[dev].buttons[btn].cookie, &event));
|
406
|
+
|
407
|
+
if (event.value >= 1)
|
408
|
+
result[gpButton0 + btn - gpRangeBegin] = true;
|
409
|
+
}
|
410
|
+
}
|
411
|
+
|
412
|
+
return result;
|
413
|
+
}
|
414
|
+
};
|
415
|
+
}
|
416
|
+
|
417
|
+
// Needed for char translation.
|
418
|
+
namespace Gosu
|
419
|
+
{
|
420
|
+
std::wstring macRomanToWstring(const std::string& s);
|
421
|
+
}
|
422
|
+
|
423
|
+
namespace {
|
424
|
+
const unsigned numScancodes = 128;
|
425
|
+
|
426
|
+
boost::array<wchar_t, numScancodes> idChars;
|
427
|
+
std::map<wchar_t, unsigned> charIds;
|
428
|
+
|
429
|
+
void initCharTranslation()
|
430
|
+
{
|
431
|
+
static bool initializedCharData = false;
|
432
|
+
if (initializedCharData)
|
433
|
+
return;
|
434
|
+
initializedCharData = true;
|
435
|
+
|
436
|
+
idChars.assign(0);
|
437
|
+
|
438
|
+
const void* KCHR = reinterpret_cast<const void*>(GetScriptManagerVariable(smKCHRCache));
|
439
|
+
if (!KCHR)
|
440
|
+
return;
|
441
|
+
|
442
|
+
for (int code = numScancodes - 1; code >= 0; --code)
|
443
|
+
{
|
444
|
+
UInt32 deadKeyState = 0;
|
445
|
+
UInt32 value = KeyTranslate(KCHR, code, &deadKeyState);
|
446
|
+
// If this key triggered a dead key, hit it again to obtain the actual value.
|
447
|
+
if (deadKeyState != 0)
|
448
|
+
value = KeyTranslate(KCHR, code, &deadKeyState);
|
449
|
+
|
450
|
+
// No character! Pity.
|
451
|
+
if (value == 0)
|
452
|
+
continue;
|
453
|
+
|
454
|
+
// Ignore special characters except newline.
|
455
|
+
if (value == 3)
|
456
|
+
value = 13; // convert Enter to Return
|
457
|
+
if (value < 32 && value != 13)
|
458
|
+
continue;
|
459
|
+
|
460
|
+
// Now we have a character which is *not* limited to the ASCII range. To correctly
|
461
|
+
// translate this into a wchar_t, we need to convert it based on the current locale.
|
462
|
+
// TODO: That locale stuff should be explicit. Locales always cause trouble.
|
463
|
+
|
464
|
+
std::string str(1, char(value));
|
465
|
+
wchar_t ch = Gosu::macRomanToWstring(str).at(0);
|
466
|
+
|
467
|
+
idChars[code] = ch;
|
468
|
+
charIds[ch] = code;
|
469
|
+
}
|
470
|
+
}
|
471
|
+
|
472
|
+
boost::array<bool, Gosu::numButtons> buttonStates;
|
473
|
+
}
|
474
|
+
|
475
|
+
struct Gosu::Input::Impl
|
476
|
+
{
|
477
|
+
Input& input;
|
478
|
+
NSWindow* window;
|
479
|
+
TextInput* textInput;
|
480
|
+
double mouseX, mouseY;
|
481
|
+
double mouseFactorX, mouseFactorY;
|
482
|
+
|
483
|
+
unsigned currentMods;
|
484
|
+
|
485
|
+
struct WaitingButton
|
486
|
+
{
|
487
|
+
Button btn;
|
488
|
+
bool down;
|
489
|
+
WaitingButton(unsigned btnId, bool down) : btn(btnId), down(down) {}
|
490
|
+
};
|
491
|
+
std::vector<WaitingButton> queue;
|
492
|
+
|
493
|
+
Impl(Input& input)
|
494
|
+
: input(input), textInput(0), mouseFactorX(1), mouseFactorY(1), currentMods(0)
|
495
|
+
{
|
496
|
+
}
|
497
|
+
|
498
|
+
void enqueue(unsigned btnId, bool down)
|
499
|
+
{
|
500
|
+
queue.push_back(WaitingButton(btnId, down));
|
501
|
+
}
|
502
|
+
|
503
|
+
void updateMods(unsigned newMods)
|
504
|
+
{
|
505
|
+
const unsigned ids[8] = { kbLeftShift, kbLeftControl,
|
506
|
+
kbLeftAlt, kbLeftMeta,
|
507
|
+
kbRightShift, kbRightControl,
|
508
|
+
kbRightAlt, kbRightMeta };
|
509
|
+
const unsigned bits[8] = { NX_DEVICELSHIFTKEYMASK, NX_DEVICELCTLKEYMASK,
|
510
|
+
NX_DEVICELALTKEYMASK, NX_DEVICELCMDKEYMASK,
|
511
|
+
NX_DEVICERSHIFTKEYMASK, NX_DEVICERCTLKEYMASK,
|
512
|
+
NX_DEVICERALTKEYMASK, NX_DEVICERCMDKEYMASK };
|
513
|
+
|
514
|
+
for (unsigned i = 0; i < 8; ++i)
|
515
|
+
if ((currentMods & bits[i]) != (newMods & bits[i]))
|
516
|
+
enqueue(ids[i], (newMods & bits[i]) != 0);
|
517
|
+
|
518
|
+
currentMods = newMods;
|
519
|
+
}
|
520
|
+
};
|
521
|
+
|
522
|
+
Gosu::Input::Input(void* window)
|
523
|
+
: pimpl(new Impl(*this))
|
524
|
+
{
|
525
|
+
pimpl->window = static_cast<NSWindow*>(window);
|
526
|
+
buttonStates.assign(false);
|
527
|
+
initCharTranslation();
|
528
|
+
}
|
529
|
+
|
530
|
+
Gosu::Input::~Input()
|
531
|
+
{
|
532
|
+
}
|
533
|
+
|
534
|
+
bool Gosu::Input::feedNSEvent(void* event)
|
535
|
+
{
|
536
|
+
NSEvent* ev = (NSEvent*)event;
|
537
|
+
unsigned type = [ev type];
|
538
|
+
|
539
|
+
if (type == NSKeyDown && textInput() && textInput()->feedNSEvent(event))
|
540
|
+
return true;
|
541
|
+
|
542
|
+
if (type == NSKeyDown && [ev isARepeat])
|
543
|
+
return false;
|
544
|
+
|
545
|
+
// Process modifier keys.
|
546
|
+
unsigned mods = [ev modifierFlags];
|
547
|
+
if (mods != pimpl->currentMods)
|
548
|
+
pimpl->updateMods(mods);
|
549
|
+
|
550
|
+
|
551
|
+
// Handle mouse input.
|
552
|
+
switch (type)
|
553
|
+
{
|
554
|
+
case NSLeftMouseDown:
|
555
|
+
pimpl->enqueue(msLeft, true);
|
556
|
+
return true;
|
557
|
+
case NSLeftMouseUp:
|
558
|
+
pimpl->enqueue(msLeft, false);
|
559
|
+
return true;
|
560
|
+
case NSRightMouseDown:
|
561
|
+
pimpl->enqueue(msRight, true);
|
562
|
+
return true;
|
563
|
+
case NSRightMouseUp:
|
564
|
+
pimpl->enqueue(msRight, false);
|
565
|
+
return true;
|
566
|
+
case NSScrollWheel:
|
567
|
+
if ([ev deltaY] > 0)
|
568
|
+
{
|
569
|
+
pimpl->enqueue(msWheelUp, true);
|
570
|
+
pimpl->enqueue(msWheelUp, false);
|
571
|
+
}
|
572
|
+
else if ([ev deltaY] < 0)
|
573
|
+
{
|
574
|
+
pimpl->enqueue(msWheelDown, true);
|
575
|
+
pimpl->enqueue(msWheelDown, false);
|
576
|
+
}
|
577
|
+
else
|
578
|
+
return false;
|
579
|
+
return true;
|
580
|
+
}
|
581
|
+
|
582
|
+
// Handle other keys.
|
583
|
+
if (type == NSKeyDown || type == NSKeyUp)
|
584
|
+
{
|
585
|
+
pimpl->enqueue([ev keyCode], type == NSKeyDown);
|
586
|
+
return true;
|
587
|
+
}
|
588
|
+
|
589
|
+
return false;
|
590
|
+
}
|
591
|
+
|
592
|
+
wchar_t Gosu::Input::idToChar(Button btn)
|
593
|
+
{
|
594
|
+
if (btn.getId() < numScancodes)
|
595
|
+
return idChars[btn.getId()];
|
596
|
+
else
|
597
|
+
return 0;
|
598
|
+
}
|
599
|
+
|
600
|
+
Gosu::Button Gosu::Input::charToId(wchar_t ch)
|
601
|
+
{
|
602
|
+
std::map<wchar_t, unsigned>::const_iterator iter = charIds.find(ch);
|
603
|
+
if (iter == charIds.end())
|
604
|
+
return noButton;
|
605
|
+
return Gosu::Button(iter->second);
|
606
|
+
}
|
607
|
+
|
608
|
+
bool Gosu::Input::down(Gosu::Button btn) const
|
609
|
+
{
|
610
|
+
return buttonStates.at(btn.getId());
|
611
|
+
}
|
612
|
+
|
613
|
+
double Gosu::Input::mouseX() const
|
614
|
+
{
|
615
|
+
return pimpl->mouseX * pimpl->mouseFactorX;
|
616
|
+
}
|
617
|
+
|
618
|
+
double Gosu::Input::mouseY() const
|
619
|
+
{
|
620
|
+
return pimpl->mouseY * pimpl->mouseFactorY;
|
621
|
+
}
|
622
|
+
|
623
|
+
void Gosu::Input::setMouseFactors(double factorX, double factorY)
|
624
|
+
{
|
625
|
+
pimpl->mouseFactorX = factorX;
|
626
|
+
pimpl->mouseFactorY = factorY;
|
627
|
+
}
|
628
|
+
|
629
|
+
void Gosu::Input::update()
|
630
|
+
{
|
631
|
+
NSPoint mousePos = [NSEvent mouseLocation];
|
632
|
+
if (pimpl->window)
|
633
|
+
{
|
634
|
+
mousePos = [pimpl->window convertScreenToBase: mousePos];
|
635
|
+
mousePos.y = [[pimpl->window contentView] frame].size.height - mousePos.y;
|
636
|
+
}
|
637
|
+
else
|
638
|
+
mousePos.y = CGDisplayBounds(CGMainDisplayID()).size.height - mousePos.y;
|
639
|
+
pimpl->mouseX = mousePos.x;
|
640
|
+
pimpl->mouseY = mousePos.y;
|
641
|
+
|
642
|
+
for (unsigned i = 0; i < pimpl->queue.size(); ++i)
|
643
|
+
{
|
644
|
+
Impl::WaitingButton& wb = pimpl->queue[i];
|
645
|
+
buttonStates.at(wb.btn.getId()) = wb.down;
|
646
|
+
if (wb.down && onButtonDown)
|
647
|
+
onButtonDown(wb.btn);
|
648
|
+
else if (!wb.down && onButtonUp)
|
649
|
+
onButtonUp(wb.btn);
|
650
|
+
}
|
651
|
+
pimpl->queue.clear();
|
652
|
+
|
653
|
+
static System sys;
|
654
|
+
boost::array<bool, gpNum> gpState = sys.poll();
|
655
|
+
for (unsigned i = 0; i < gpNum; ++i)
|
656
|
+
{
|
657
|
+
if (buttonStates[i + gpRangeBegin] != gpState[i])
|
658
|
+
{
|
659
|
+
buttonStates[i + gpRangeBegin] = gpState[i];
|
660
|
+
if (gpState[i] && onButtonDown)
|
661
|
+
onButtonDown(Button(gpRangeBegin + i));
|
662
|
+
else if (!gpState[i] && onButtonUp)
|
663
|
+
onButtonUp(Button(gpRangeBegin + i));
|
664
|
+
}
|
665
|
+
}
|
666
|
+
}
|
667
|
+
|
668
|
+
Gosu::TextInput* Gosu::Input::textInput() const
|
669
|
+
{
|
670
|
+
return pimpl->textInput;
|
671
|
+
}
|
672
|
+
|
673
|
+
void Gosu::Input::setTextInput(TextInput* textInput)
|
674
|
+
{
|
675
|
+
pimpl->textInput = textInput;
|
676
|
+
}
|
677
|
+
|