1 ////////////////////////////////////////////////////////////
2 //
3 // SFML - Simple and Fast Multimedia Library
4 // Copyright (C) 2007-2018 Marco Antognini (antognini.marco@gmail.com),
5 //                         Laurent Gomila (laurent@sfml-dev.org)
6 //
7 // This software is provided 'as-is', without any express or implied warranty.
8 // In no event will the authors be held liable for any damages arising from the use of this software.
9 //
10 // Permission is granted to anyone to use this software for any purpose,
11 // including commercial applications, and to alter it and redistribute it freely,
12 // subject to the following restrictions:
13 //
14 // 1. The origin of this software must not be misrepresented;
15 //    you must not claim that you wrote the original software.
16 //    If you use this software in a product, an acknowledgment
17 //    in the product documentation would be appreciated but is not required.
18 //
19 // 2. Altered source versions must be plainly marked as such,
20 //    and must not be misrepresented as being the original software.
21 //
22 // 3. This notice may not be removed or altered from any source distribution.
23 //
24 ////////////////////////////////////////////////////////////
25 
26 #ifndef SFML_HIDINPUTMANAGER_HPP
27 #define SFML_HIDINPUTMANAGER_HPP
28 
29 ////////////////////////////////////////////////////////////
30 // Headers
31 ////////////////////////////////////////////////////////////
32 #include <SFML/Window/JoystickImpl.hpp>
33 #include <SFML/Window/Keyboard.hpp>
34 #include <SFML/System/NonCopyable.hpp>
35 #include <Carbon/Carbon.h>
36 #include <IOKit/hid/IOHIDDevice.h>
37 #include <IOKit/hid/IOHIDManager.h>
38 #include <vector>
39 
40 namespace sf
41 {
42 namespace priv
43 {
44 
45 typedef std::vector<IOHIDElementRef> IOHIDElements;
46 
47 ////////////////////////////////////////////////////////////
48 /// \brief sf::priv::InputImpl helper
49 ///
50 /// This class manage as a singleton instance the keyboard state.
51 /// Its purpose is to help sf::priv::InputImpl class.
52 ///
53 ////////////////////////////////////////////////////////////
54 class HIDInputManager : NonCopyable
55 {
56 public:
57 
58     ////////////////////////////////////////////////////////////
59     /// \brief Get the unique instance of the class
60     ///
61     /// \note Private use only
62     ///
63     /// \return Reference to the HIDInputManager instance
64     ///
65     ////////////////////////////////////////////////////////////
66     static HIDInputManager& getInstance();
67 
68     ////////////////////////////////////////////////////////////
69     /// \brief Check if a key is pressed
70     ///
71     /// \param key Key to check
72     ///
73     /// \return True if the key is pressed, false otherwise
74     ///
75     ////////////////////////////////////////////////////////////
76     bool isKeyPressed(Keyboard::Key key);
77 
78 public:
79 
80     ////////////////////////////////////////////////////////////
81     /// \brief Get the usb location ID of a given device
82     ///
83     /// This location ID is unique and can be used a usb port identifier
84     ///
85     /// \param device HID device to query
86     /// \return the device's location ID or 0 if something went wrong
87     ///
88     ////////////////////////////////////////////////////////////
89     static long getLocationID(IOHIDDeviceRef device);
90 
91     ////////////////////////////////////////////////////////////
92     /// \brief Create a mask (dictionary) for an IOHIDManager
93     ///
94     /// \param page  HID page
95     /// \param usage HID usage page
96     /// \return a retained CFDictionaryRef
97     ///
98     ////////////////////////////////////////////////////////////
99     static CFDictionaryRef copyDevicesMask(UInt32 page, UInt32 usage);
100 
101     ////////////////////////////////////////////////////////////
102     /// Try to convert a character into a SFML key code.
103     ///
104     /// Return sf::Keyboard::Unknown if it doesn't match any 'localized' keys.
105     ///
106     /// By 'localized' I mean keys that depend on the keyboard layout
107     /// and might not be the same as the US keycode in some country
108     /// (e.g. the keys 'Y' and 'Z' are switched on QWERTZ keyboard and
109     /// US keyboard layouts.)
110     ///
111     ////////////////////////////////////////////////////////////
112     static Keyboard::Key localizedKeys(UniChar ch);
113 
114     ////////////////////////////////////////////////////////////
115     /// Try to convert a virtual keycode into a SFML key code.
116     ///
117     /// Return sf::Keyboard::Unknown if the keycode is unknown.
118     ///
119     ////////////////////////////////////////////////////////////
120     static Keyboard::Key nonLocalizedKeys(UniChar virtualKeycode);
121 
122 private:
123 
124     ////////////////////////////////////////////////////////////
125     /// \brief Default constructor
126     ///
127     ////////////////////////////////////////////////////////////
128     HIDInputManager();
129 
130     ////////////////////////////////////////////////////////////
131     /// \brief Destructor
132     ///
133     ////////////////////////////////////////////////////////////
134     ~HIDInputManager();
135 
136     ////////////////////////////////////////////////////////////
137     /// \brief Initialize the keyboard part of this class
138     ///
139     /// If something went wrong freeUp is called
140     ///
141     ////////////////////////////////////////////////////////////
142     void initializeKeyboard();
143 
144     ////////////////////////////////////////////////////////////
145     /// \brief Load the given keyboard into m_keys
146     ///
147     /// If the given keyboard has no key this function simply
148     /// returns. freeUp is _not_ called because this is not fatal.
149     ///
150     /// \param keyboard Keyboard to load
151     ///
152     ////////////////////////////////////////////////////////////
153     void loadKeyboard(IOHIDDeviceRef keyboard);
154 
155     ////////////////////////////////////////////////////////////
156     /// \brief Load the given key into m_keys
157     ///
158     /// freeUp is _not_ called by this function.
159     ///
160     /// \param key Key to load
161     ///
162     ////////////////////////////////////////////////////////////
163     void loadKey(IOHIDElementRef key);
164 
165     ////////////////////////////////////////////////////////////
166     /// \brief Release all resources
167     ///
168     /// Close all connections to any devices, if required
169     /// Set m_isValid to false
170     ///
171     ////////////////////////////////////////////////////////////
172     void freeUp();
173 
174     ////////////////////////////////////////////////////////////
175     /// \brief Filter the devices and return them
176     ///
177     /// freeUp is _not_ called by this function.
178     ///
179     /// \param page  HID page like kHIDPage_GenericDesktop
180     /// \param usage HID usage page like kHIDUsage_GD_Keyboard or kHIDUsage_GD_Mouse
181     /// \return a retained CFSetRef of IOHIDDeviceRef or NULL
182     ///
183     ////////////////////////////////////////////////////////////
184     CFSetRef copyDevices(UInt32 page, UInt32 usage);
185 
186     ////////////////////////////////////////////////////////////
187     /// \brief Check if a key is pressed
188     ///
189     /// \param elements HID elements mapping to this key
190     ///
191     /// \return True if the key is pressed, false otherwise
192     ///
193     /// \see isKeyPressed, isMouseButtonPressed
194     ///
195     ////////////////////////////////////////////////////////////
196     bool isPressed(IOHIDElements& elements);
197 
198     ////////////////////////////////////////////////////////////
199     /// \brief Convert a HID key usage to its corresponding virtual code
200     ///
201     /// See IOHIDUsageTables.h
202     ///
203     /// \param usage Any kHIDUsage_Keyboard* usage
204     /// \return the virtual code associate with the given HID key usage
205     ///         or 0xff if it is associate with no virtual code
206     ///
207     ////////////////////////////////////////////////////////////
208     static UInt8 usageToVirtualCode(UInt32 usage);
209 
210 private:
211 
212     ////////////////////////////////////////////////////////////
213     // Member data
214     ////////////////////////////////////////////////////////////
215     bool              m_isValid;                    ///< If any error occurs this variable is false
216     CFDataRef         m_layoutData;                 ///< CFData containing the layout
217     UCKeyboardLayout* m_layout;                     ///< Current Keyboard Layout
218     IOHIDManagerRef   m_manager;                    ///< HID Manager
219 
220     IOHIDElements     m_keys[Keyboard::KeyCount];   ///< All the keys on any connected keyboard
221 
222     ////////////////////////////////////////////////////////////
223     /// m_keys' index corresponds to sf::Keyboard::Key enum.
224     /// if no key is assigned with key XYZ then m_keys[XYZ].size() == 0.
225     /// if there are several keyboards connected and several HID keys associate
226     /// with the same sf::Keyboard::Key then m_keys[XYZ] contains all these
227     /// HID keys.
228     ///
229     ////////////////////////////////////////////////////////////
230 };
231 
232 } // namespace priv
233 
234 } // namespace sf
235 
236 #endif
237