Add the digital interface, running MMTTY under Wine
MMTTY and 2Tone have no socket or pipe interface: N1MM hosts XMMT.ocx and exchanges window messages with the engine. A Linux process cannot load that control, so bridge/nonemm-mmtty-bridge.exe hosts it under Wine and passes lines over its standard input and output. docs/digital-bridge.md states the protocol and what the control needs. The window is N1MM's: receive pane with coloured callsigns, grab list, call stacking, twenty-four macro buttons and the engine controls. One left click copies what is under it — a callsign to the callsign box, anything else to the exchange box the contest keeps for that kind of value. Config > Digital registers XMMT.ocx in the Wine prefix on its own, making the prefix first if it is not there. The engine, the bridge and the control start at the copies shipped beside the program. The bridge reads the control's own events. OnTranslateMessage carries only the messages the control has no event for, so nothing was ever decoded through it. hamlib's data mode names read as digital modes now, and a mode typed into the callsign box changes mode the way a frequency changes band, so a station with no radio can reach RTTY at all. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RoGtneMQaz4M9w7Kk49AVD
This commit is contained in:
70
bridge/ControlSite.h
Normal file
70
bridge/ControlSite.h
Normal file
@@ -0,0 +1,70 @@
|
||||
#pragma once
|
||||
|
||||
#include <windows.h>
|
||||
#include <ole2.h>
|
||||
|
||||
// The least a window has to provide for an ActiveX control to activate in it.
|
||||
// XMMT.ocx draws nothing we look at, so every method that decides layout,
|
||||
// menus or scrolling answers with the default.
|
||||
class ControlSite : public IOleClientSite, public IOleInPlaceSite, public IOleInPlaceFrame {
|
||||
public:
|
||||
explicit ControlSite(HWND parent) : parent_(parent) {}
|
||||
virtual ~ControlSite() = default;
|
||||
|
||||
STDMETHODIMP QueryInterface(REFIID iid, void** out) override;
|
||||
STDMETHODIMP_(ULONG) AddRef() override;
|
||||
STDMETHODIMP_(ULONG) Release() override;
|
||||
|
||||
// IOleClientSite
|
||||
STDMETHODIMP SaveObject() override { return S_OK; }
|
||||
STDMETHODIMP GetMoniker(DWORD, DWORD, IMoniker** moniker) override {
|
||||
*moniker = nullptr;
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
STDMETHODIMP GetContainer(IOleContainer** container) override {
|
||||
*container = nullptr;
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
STDMETHODIMP ShowObject() override { return S_OK; }
|
||||
STDMETHODIMP OnShowWindow(BOOL) override { return S_OK; }
|
||||
STDMETHODIMP RequestNewObjectLayout() override { return E_NOTIMPL; }
|
||||
|
||||
// IOleWindow, shared by the site and the frame
|
||||
STDMETHODIMP GetWindow(HWND* window) override {
|
||||
*window = parent_;
|
||||
return S_OK;
|
||||
}
|
||||
STDMETHODIMP ContextSensitiveHelp(BOOL) override { return E_NOTIMPL; }
|
||||
|
||||
// IOleInPlaceSite
|
||||
STDMETHODIMP CanInPlaceActivate() override { return S_OK; }
|
||||
STDMETHODIMP OnInPlaceActivate() override { return S_OK; }
|
||||
STDMETHODIMP OnUIActivate() override { return S_OK; }
|
||||
STDMETHODIMP GetWindowContext(IOleInPlaceFrame** frame, IOleInPlaceUIWindow** document,
|
||||
LPRECT position, LPRECT clip,
|
||||
LPOLEINPLACEFRAMEINFO info) override;
|
||||
STDMETHODIMP Scroll(SIZE) override { return E_NOTIMPL; }
|
||||
STDMETHODIMP OnUIDeactivate(BOOL) override { return S_OK; }
|
||||
STDMETHODIMP OnInPlaceDeactivate() override { return S_OK; }
|
||||
STDMETHODIMP DiscardUndoState() override { return E_NOTIMPL; }
|
||||
STDMETHODIMP DeactivateAndUndo() override { return E_NOTIMPL; }
|
||||
STDMETHODIMP OnPosRectChange(LPCRECT) override { return S_OK; }
|
||||
|
||||
// IOleInPlaceUIWindow
|
||||
STDMETHODIMP GetBorder(LPRECT) override { return E_NOTIMPL; }
|
||||
STDMETHODIMP RequestBorderSpace(LPCBORDERWIDTHS) override { return E_NOTIMPL; }
|
||||
STDMETHODIMP SetBorderSpace(LPCBORDERWIDTHS) override { return E_NOTIMPL; }
|
||||
STDMETHODIMP SetActiveObject(IOleInPlaceActiveObject*, LPCOLESTR) override { return S_OK; }
|
||||
|
||||
// IOleInPlaceFrame
|
||||
STDMETHODIMP InsertMenus(HMENU, LPOLEMENUGROUPWIDTHS) override { return E_NOTIMPL; }
|
||||
STDMETHODIMP SetMenu(HMENU, HOLEMENU, HWND) override { return S_OK; }
|
||||
STDMETHODIMP RemoveMenus(HMENU) override { return E_NOTIMPL; }
|
||||
STDMETHODIMP SetStatusText(LPCOLESTR) override { return S_OK; }
|
||||
STDMETHODIMP EnableModeless(BOOL) override { return S_OK; }
|
||||
STDMETHODIMP TranslateAccelerator(LPMSG, WORD) override { return S_FALSE; }
|
||||
|
||||
private:
|
||||
HWND parent_;
|
||||
ULONG references_ = 1;
|
||||
};
|
||||
Reference in New Issue
Block a user