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