Introduction
Have you ever seen those nice Unix\Linux transparent terminals and thought - why can't I get one of those for Windows?
Well, the search is over - well, not really, still some way to go, but this will be a good place to start.
Credits
First things first though, this article (and project for that matter) is based on articles and code from The Code Project site and I mainly integrated the code. I will go over a few of the problems I've encountered but without further ado, here they are:
- Transparency.
- Fonts.
- Completion ComboBox.
- Resize and Move messages.
- Color picker control.
- Fancy controls.
- Console I\O redirector.
- Anybody I forgot and deserves credit.
Implementation Notes
I encountered a few problems while writing this little application, and it might be interesting for some to understand what these problems where so they\you can avoid them (or solve them faster) in the future.
Sending the commands from the combo to the I\O redirector
You would expect a ComboBox
to have an OnEnter
event, wouldn't you? Nope, it doesn't. So what do you do when you type your command and want to send it to the console? Here's how I did it:
First, I provided an interface for the event handler. The handler registers itself on the combo and can handle events like keystrokes etc. The combo's job is to call the handler's function when the event occurs. In this case, I handled the ENTER event and F1 (restarting the console when an operation takes too long for my liking - anybody said "tracert" ?).
class Eventer
{
public:
Eventer(void);
virtual ~Eventer(void);
virtual void PerformAction(const CString& strCmd) = 0;
virtual void PerformSpecialAction(UINT nAction) = 0;
};
The next thing to do was to inherit the interface and register on the combo:
class CTConsoleView : public CFormView, Eventer
m_combo.Register(this);
Now we need to catch those events like ENTER and perform the action we want - in this case, pass the input to the console. Another event that is caught is F1 - it's much harder to handle a CTRL+C in the combo, but you might want to imitate the functionality of the command, hence F1 - F12 keystrokes are caught and can be handled. As an example, I handled F1 to restart the console.
BOOL CHMXComboBox::PreTranslateMessage(MSG* pMsg)
{
InitToolTip();
m_tt.RelayEvent(pMsg);
if (pMsg->message == WM_KEYDOWN)
{
m_bAutoComplete = TRUE;
int nVirtKey = (int) pMsg->wParam;
if (nVirtKey == VK_DELETE || nVirtKey == VK_BACK)
m_bAutoComplete = FALSE;
if (nVirtKey == VK_RETURN)
{
CString sText;
GetWindowText(sText);
if(FindString(0,sText) == CB_ERR)
AddString(sText);
for(int i(0);i < m_arrEventers.GetSize(); i++)
{
Eventer* pEvent = (Eventer*)m_arrEventers[i];
Event->PerformAction(sText);
}
}
if (nVirtKey >= VK_F1 && nVirtKey <= VK_F12)
{
for(int i(0);i < m_arrEventers.GetSize(); i++)
{
Eventer* pEvent = (Eventer*)m_arrEventers[i];
pEvent->PerformSpecialAction(nVirtKey);
}
}
}
And finally, handling the event (for example, we wouldn't want to send the "edit" command to the console because the cmd.exe process opens the DOS edit utility). So, in order to override it, we have to perform some sort of string parsing on the command.
void CTConsoleView::PerformAction(const CString& strCmd)
{
if(!strCmd.Left(4).CompareNoCase("edit"))
{
CString cmd = "notepad.exe ";
cmd += strCmd.Right(strCmd.GetLength()-4);
WinExec(cmd, SW_SHOW);
return;
}
m_redir.Printf("%s\r\n", strCmd);
m_combo.SetWindowText("");
}
Final Notes
Well, I think that's enough for now. If you have any questions, you are welcome to submit them in the comments section, or email me.
Good coding.
Asa.