iPlug2 - C++ Audio Plug-in Framework
Loading...
Searching...
No Matches
IPlugVST3_View.h
1/*
2 ==============================================================================
3
4 This file is part of the iPlug 2 library. Copyright (C) the iPlug 2 developers.
5
6 See LICENSE.txt for more info.
7
8 ==============================================================================
9*/
10
11#pragma once
12#include "base/source/fstring.h"
13#include "pluginterfaces/gui/iplugviewcontentscalesupport.h"
14#include "pluginterfaces/base/keycodes.h"
15
16#include "IPlugStructs.h"
17
19template <class T>
20class IPlugVST3View : public Steinberg::CPluginView
21 , public Steinberg::IPlugViewContentScaleSupport
22{
23public:
24 IPlugVST3View(T& owner)
25 : mOwner(owner)
26 {
27 mOwner.addRef();
28 }
29
30 ~IPlugVST3View()
31 {
32 mOwner.release();
33 }
34
35 IPlugVST3View(const IPlugVST3View&) = delete;
36 IPlugVST3View& operator=(const IPlugVST3View&) = delete;
37
38 Steinberg::tresult PLUGIN_API isPlatformTypeSupported(Steinberg::FIDString type) override
39 {
40 if (mOwner.HasUI()) // for no editor plugins
41 {
42#ifdef OS_WIN
43 if (strcmp(type, Steinberg::kPlatformTypeHWND) == 0)
44 return Steinberg::kResultTrue;
45
46#elif defined OS_MAC
47 if (strcmp(type, Steinberg::kPlatformTypeNSView) == 0)
48 return Steinberg::kResultTrue;
49#endif
50 }
51
52 return Steinberg::kResultFalse;
53 }
54
55 Steinberg::tresult PLUGIN_API onSize(Steinberg::ViewRect* pSize) override
56 {
57 TRACE
58
59 if (pSize)
60 {
61 rect = *pSize;
62 mOwner.OnParentWindowResize(rect.getWidth(), rect.getHeight());
63 }
64
65 return Steinberg::kResultTrue;
66 }
67
68 Steinberg::tresult PLUGIN_API getSize(Steinberg::ViewRect* pSize) override
69 {
70 TRACE
71
72 if (mOwner.HasUI())
73 {
74 *pSize = Steinberg::ViewRect(0, 0, mOwner.GetEditorWidth(), mOwner.GetEditorHeight());
75
76 return Steinberg::kResultTrue;
77 }
78 else
79 {
80 return Steinberg::kResultFalse;
81 }
82 }
83
84 Steinberg::tresult PLUGIN_API canResize() override
85 {
86 if (mOwner.HasUI() && mOwner.GetHostResizeEnabled())
87 {
88 return Steinberg::kResultTrue;
89 }
90
91 return Steinberg::kResultFalse;
92 }
93
94 Steinberg::tresult PLUGIN_API checkSizeConstraint(Steinberg::ViewRect* pRect) override
95 {
96 int w = pRect->getWidth();
97 int h = pRect->getHeight();
98
99 if(!mOwner.ConstrainEditorResize(w, h))
100 {
101 pRect->right = pRect->left + w;
102 pRect->bottom = pRect->top + h;
103 }
104
105 return Steinberg::kResultTrue;
106 }
107
108 Steinberg::tresult PLUGIN_API attached(void* pParent, Steinberg::FIDString type) override
109 {
110 if (mOwner.HasUI())
111 {
112 void* pView = nullptr;
113#ifdef OS_WIN
114 if (strcmp(type, Steinberg::kPlatformTypeHWND) == 0)
115 pView = mOwner.OpenWindow(pParent);
116#elif defined OS_MAC
117 if (strcmp(type, Steinberg::kPlatformTypeNSView) == 0)
118 pView = mOwner.OpenWindow(pParent);
119 else // Carbon
120 return Steinberg::kResultFalse;
121#endif
122 return Steinberg::kResultTrue;
123 }
124
125 return Steinberg::kResultFalse;
126 }
127
128 Steinberg::tresult PLUGIN_API removed() override
129 {
130 if (mOwner.HasUI())
131 mOwner.CloseWindow();
132
133 return CPluginView::removed();
134 }
135
136 Steinberg::tresult PLUGIN_API setContentScaleFactor(ScaleFactor factor) override
137 {
138 mOwner.SetScreenScale(factor);
139
140 return Steinberg::kResultOk;
141 }
142
143 Steinberg::tresult PLUGIN_API queryInterface(const Steinberg::TUID _iid, void** obj) override
144 {
145 QUERY_INTERFACE(_iid, obj, IPlugViewContentScaleSupport::iid, IPlugViewContentScaleSupport)
146 *obj = 0;
147 return CPluginView::queryInterface(_iid, obj);
148 }
149
150 Steinberg::tresult PLUGIN_API onKeyDown (Steinberg::char16 key, Steinberg::int16 keyMsg, Steinberg::int16 modifiers) override
151 {
152 // Workaround for Reaper's funky key/keyMsg
153 if (mOwner.GetHost() == iplug::EHost::kHostReaper)
154 {
155 if (keyMsg == Steinberg::VirtualKeyCodes::KEY_SPACE)
156 {
157 iplug::IKeyPress keyPress { " ",
158 iplug::kVK_SPACE,
159 static_cast<bool>(modifiers & Steinberg::kShiftKey),
160 static_cast<bool>(modifiers & Steinberg::kCommandKey),
161 static_cast<bool>(modifiers & Steinberg::kAlternateKey)};
162
163 return mOwner.OnKeyDown(keyPress) ? Steinberg::kResultTrue : Steinberg::kResultFalse;
164 }
165 else
166 {
167 return Steinberg::kResultFalse;
168 }
169 }
170 else
171 {
172 return mOwner.OnKeyDown(TranslateKeyMessage(key, keyMsg, modifiers)) ? Steinberg::kResultTrue : Steinberg::kResultFalse;
173 }
174 }
175
176 Steinberg::tresult PLUGIN_API onKeyUp (Steinberg::char16 key, Steinberg::int16 keyMsg, Steinberg::int16 modifiers) override
177 {
178 // Workaround for Reaper's funky key/keyMsg
179 if (mOwner.GetHost() == iplug::EHost::kHostReaper)
180 {
181 if (keyMsg == Steinberg::VirtualKeyCodes::KEY_SPACE)
182 {
183 iplug::IKeyPress keyPress { " ", iplug::kVK_SPACE,
184 static_cast<bool>(modifiers & Steinberg::kShiftKey),
185 static_cast<bool>(modifiers & Steinberg::kCommandKey),
186 static_cast<bool>(modifiers & Steinberg::kAlternateKey)};
187
188 return mOwner.OnKeyUp(keyPress) ? Steinberg::kResultTrue : Steinberg::kResultFalse;
189 }
190 else
191 {
192 return Steinberg::kResultFalse;
193 }
194 }
195 else
196 {
197 return mOwner.OnKeyUp(TranslateKeyMessage(key, keyMsg, modifiers)) ? Steinberg::kResultTrue : Steinberg::kResultFalse;
198 }
199 }
200
201 DELEGATE_REFCOUNT(Steinberg::CPluginView)
202
203#pragma mark -
204
205 static int AsciiToVK(int ascii)
206 {
207 #ifdef OS_WIN
208 HKL layout = GetKeyboardLayout(0);
209 return VkKeyScanExA((CHAR)ascii, layout);
210 #else
211 // Numbers and uppercase alpha chars map directly to VK
212 if ((ascii >= 0x30 && ascii <= 0x39) || (ascii >= 0x41 && ascii <= 0x5A))
213 {
214 return ascii;
215 }
216
217 // Lowercase alpha chars map to VK but need shifting
218 if (ascii >= 0x61 && ascii <= 0x7A)
219 {
220 return ascii - 0x20;
221 }
222
223 return iplug::kVK_NONE;
224 #endif
225 }
226
227 static int VSTKeyCodeToVK (Steinberg::int16 code, char ascii)
228 {
229 // If the keycode provided by the host is 0, we can still calculate the VK from the ascii value
230 // NOTE: VKEY_EQUALS Doesn't seem to map to a Windows VK, so get the VK from the ascii char instead
231 if (code == 0 || code == Steinberg::KEY_EQUALS)
232 {
233 return AsciiToVK(ascii);
234 }
235
236 using namespace Steinberg;
237 using namespace iplug;
238
239 switch (code)
240 {
241 case KEY_BACK: return kVK_BACK;
242 case KEY_TAB: return kVK_TAB;
243 case KEY_CLEAR: return kVK_CLEAR;
244 case KEY_RETURN: return kVK_RETURN;
245 case KEY_PAUSE: return kVK_PAUSE;
246 case KEY_ESCAPE: return kVK_ESCAPE;
247 case KEY_SPACE: return kVK_SPACE;
248 case KEY_NEXT: return kVK_NEXT;
249 case KEY_END: return kVK_END;
250 case KEY_HOME: return kVK_HOME;
251 case KEY_LEFT: return kVK_LEFT;
252 case KEY_UP: return kVK_UP;
253 case KEY_RIGHT: return kVK_RIGHT;
254 case KEY_DOWN: return kVK_DOWN;
255 case KEY_PAGEUP: return kVK_PRIOR;
256 case KEY_PAGEDOWN: return kVK_NEXT;
257 case KEY_SELECT: return kVK_SELECT;
258 case KEY_PRINT: return kVK_PRINT;
259 case KEY_ENTER: return kVK_RETURN;
260 case KEY_SNAPSHOT: return kVK_SNAPSHOT;
261 case KEY_INSERT: return kVK_INSERT;
262 case KEY_DELETE: return kVK_DELETE;
263 case KEY_HELP: return kVK_HELP;
264 case KEY_NUMPAD0: return kVK_NUMPAD0;
265 case KEY_NUMPAD1: return kVK_NUMPAD1;
266 case KEY_NUMPAD2: return kVK_NUMPAD2;
267 case KEY_NUMPAD3: return kVK_NUMPAD3;
268 case KEY_NUMPAD4: return kVK_NUMPAD4;
269 case KEY_NUMPAD5: return kVK_NUMPAD5;
270 case KEY_NUMPAD6: return kVK_NUMPAD6;
271 case KEY_NUMPAD7: return kVK_NUMPAD7;
272 case KEY_NUMPAD8: return kVK_NUMPAD8;
273 case KEY_NUMPAD9: return kVK_NUMPAD9;
274 case KEY_MULTIPLY: return kVK_MULTIPLY;
275 case KEY_ADD: return kVK_ADD;
276 case KEY_SEPARATOR: return kVK_SEPARATOR;
277 case KEY_SUBTRACT: return kVK_SUBTRACT;
278 case KEY_DECIMAL: return kVK_DECIMAL;
279 case KEY_DIVIDE: return kVK_DIVIDE;
280 case KEY_F1: return kVK_F1;
281 case KEY_F2: return kVK_F2;
282 case KEY_F3: return kVK_F3;
283 case KEY_F4: return kVK_F4;
284 case KEY_F5: return kVK_F5;
285 case KEY_F6: return kVK_F6;
286 case KEY_F7: return kVK_F7;
287 case KEY_F8: return kVK_F8;
288 case KEY_F9: return kVK_F9;
289 case KEY_F10: return kVK_F10;
290 case KEY_F11: return kVK_F11;
291 case KEY_F12: return kVK_F12;
292 case KEY_NUMLOCK: return kVK_NUMLOCK;
293 case KEY_SCROLL: return kVK_SCROLL;
294 case KEY_SHIFT: return kVK_SHIFT;
295 case KEY_CONTROL: return kVK_CONTROL;
296 case KEY_ALT: return kVK_MENU;
297 case KEY_EQUALS: return kVK_NONE;
298 }
299
300 if(code >= VKEY_FIRST_ASCII)
301 return (code - VKEY_FIRST_ASCII + kVK_0);
302
303 return kVK_NONE;
304 };
305
306 static iplug::IKeyPress TranslateKeyMessage (Steinberg::char16 key, Steinberg::int16 keyMsg, Steinberg::int16 modifiers)
307 {
308 WDL_String str;
309
310 if (key == 0)
311 {
312 key = Steinberg::VirtualKeyCodeToChar((Steinberg::uint8) keyMsg);
313 }
314
315 if (key)
316 {
317 Steinberg::String keyStr(STR (" "));
318 keyStr.setChar16(0, key);
319 keyStr.toMultiByte(Steinberg::kCP_Utf8);
320 if (keyStr.length() == 1)
321 {
322 str.Set(keyStr.text8());
323 }
324 }
325
326 iplug::IKeyPress keyPress { str.Get(), VSTKeyCodeToVK(keyMsg, str.Get()[0]),
327 static_cast<bool>(modifiers & Steinberg::kShiftKey),
328 static_cast<bool>(modifiers & Steinberg::kCommandKey),
329 static_cast<bool>(modifiers & Steinberg::kAlternateKey)};
330
331 return keyPress;
332 }
333
334 void Resize(int w, int h)
335 {
336 TRACE
337
338 Steinberg::ViewRect newSize = Steinberg::ViewRect(0, 0, w, h);
339 plugFrame->resizeView(this, &newSize);
340 }
341
342 T& mOwner;
343};