3 /////////////////////////////////////////////////////////////////////////////
5 // Copyright (c) 2002-2006 David Ward
7 /////////////////////////////////////////////////////////////////////////////
10 File I/O is very simplistic. It relies on the fact that there isn't
11 going to be loads of text in the edit box. Otherwise I'm sure performance
12 would be unacceptable.
15 #include "WinCommon.h"
18 #include "../../DasherCore/Event.h"
19 #include "FilenameGUI.h"
20 #include "../resource.h"
21 #include "../../DasherCore/DasherInterfaceBase.h"
22 #include "../ActionSpeech.h"
24 #include "../Common/DasherEncodingToCP.h"
26 using namespace Dasher
;
28 using namespace WinLocalisation
;
29 using namespace WinUTF8
;
32 /////////////////////////////////////////////////////////////////////////////
34 CEdit::CEdit(CAppSettings
*pAppSettings
) : m_FontSize(0), m_FontName(""), FileHandle(INVALID_HANDLE_VALUE
),
35 m_FilenameGUI(0), threadid(0), targetwindow(0),
39 m_pAppSettings
= pAppSettings
;
41 CodePage
= GetUserCodePage();
42 m_Font
= GetCodePageFont(CodePage
, 14);
44 // FIXME - move speech into a new file
46 // Initialise speech support
50 m_pActionSpeech
= new CActionSpeech
;
51 m_pActionSpeech
->Activate();
55 ////////////////////////////////////////////////////////////////////////////
57 HWND
CEdit::Create(HWND hParent
, bool bNewWithDate
)
59 m_hWnd
= CWindowImpl
<CEdit
>::Create(hParent
, NULL
, NULL
, ES_NOHIDESEL
| WS_CHILD
| ES_MULTILINE
| WS_VSCROLL
| WS_VISIBLE
, WS_EX_CLIENTEDGE
);
63 WinLocalisation::GetResourceString(IDS_APP_TITLE
, &WindowTitle
);
64 m_FilenameGUI
= new CFilenameGUI(hParent
, WindowTitle
.c_str(), bNewWithDate
);
74 if(FileHandle
!= INVALID_HANDLE_VALUE
)
75 CloseHandle(FileHandle
);
77 m_pActionSpeech
->Deactivate();
78 delete m_pActionSpeech
;
82 void CEdit::Move(int x
, int y
, int Width
, int Height
)
84 MoveWindow( x
, y
, Width
, Height
, TRUE
);
87 void CEdit::New(const string
&filename
) {
89 UTF8string_to_wstring(filename
, newFilename
);
93 bool CEdit::Open(const string
&filename
) {
95 UTF8string_to_wstring(filename
, openFilename
);
96 return TOpen(openFilename
);
99 bool CEdit::OpenAppendMode(const string
&filename
) {
100 Tstring openFilename
;
101 UTF8string_to_wstring(filename
, openFilename
);
102 return TOpenAppendMode(openFilename
);
105 bool CEdit::SaveAs(const string
&filename
) {
106 Tstring saveFilename
;
107 UTF8string_to_wstring(filename
, saveFilename
);
108 return TSaveAs(saveFilename
);
111 /* CEdit::Save() - Save to file: {{{
113 Write a Byte Order Mark (BOM) if writing a Unicode file.
114 (Convert to wide in ANSI version and then) convert to desired codepage.
118 if(FileHandle
== INVALID_HANDLE_VALUE
) {
119 if(m_filename
== TEXT(""))
121 FileHandle
= CreateFile(m_filename
.c_str(), GENERIC_READ
| GENERIC_WRITE
, FILE_SHARE_READ
, (LPSECURITY_ATTRIBUTES
) NULL
, CREATE_ALWAYS
, FILE_ATTRIBUTE_NORMAL
, (HANDLE
) NULL
);
123 if(FileHandle
== INVALID_HANDLE_VALUE
)
127 // Truncate File to 0 bytes.
128 SetFilePointer(FileHandle
, NULL
, NULL
, FILE_BEGIN
);
129 SetEndOfFile(FileHandle
);
131 // Get all the text from the edit control
132 LRESULT EditLength
= 1 + SendMessage( WM_GETTEXTLENGTH
, 0, 0);
133 TCHAR
*EditText
= new TCHAR
[EditLength
];
134 EditLength
= SendMessage( WM_GETTEXT
, (WPARAM
) EditLength
, (LPARAM
) EditText
);
136 DWORD NumberOfBytesWritten
; // Used by WriteFile
138 // This is Windows therefore we tag Unicode files with BOMs (Byte Order Marks) {{{
139 // Then notepad and other Windows apps can recognise the files.
140 // Do NOT write BOMs in a UNIX version, they are not welcome there.
141 // The BOM is just an encoding of U+FEFF (ZERO WIDTH NO-BREAK SPACE)
142 // This is unambiguous as U+FFFE is not a valid Unicode character.
143 // There could be a menu option for this, but most users won't know what a BOM is. }}}
144 unsigned int WideLength
= 0;
145 wchar_t *WideText
= 0;
146 if((m_Encoding
== Opts::UTF16LE
) || (m_Encoding
== Opts::UTF16BE
)) {
147 // These are the UTF-16 formats. If the string isn't already in UTF-16 we need
150 WideLength
= EditLength
;
153 WideText
= new wchar_t[EditLength
+ 1];
154 WideLength
= MultiByteToWideChar(CodePage
, 0, EditText
, -1, WideText
, EditLength
+ 1);
157 switch (m_Encoding
) {
158 case Opts::UTF8
:{ // there is no byte order, but BOM tags it as a UTF-8 file
159 unsigned char BOM
[3] = { 0xEF, 0xBB, 0xBF };
160 WriteFile(FileHandle
, &BOM
, 3, &NumberOfBytesWritten
, NULL
);
161 Tstring Tmp
= EditText
;
163 wstring_to_UTF8string(EditText
, Output
);
164 WriteFile(FileHandle
, Output
.c_str(), Output
.size(), &NumberOfBytesWritten
, NULL
);
168 // TODO I am assuming this machine is LE. Do any windows (perhaps CE) machines run on BE?
169 unsigned char BOM
[2] = { 0xFF, 0xFE };
170 WriteFile(FileHandle
, &BOM
, 2, &NumberOfBytesWritten
, NULL
);
171 WriteFile(FileHandle
, WideText
, WideLength
* 2, &NumberOfBytesWritten
, NULL
);
177 case Opts::UTF16BE
:{ // UTF-16BE
178 // TODO I am again assuming this machine is LE.
179 unsigned char BOM
[2] = { 0xFE, 0xFF };
180 WriteFile(FileHandle
, &BOM
, 2, &NumberOfBytesWritten
, NULL
);
181 // There will be a better way. Perhaps use _swab instead.
182 for(unsigned int i
= 0; i
< WideLength
; i
++) {
183 const char *Hack
= (char *)&WideText
[i
];
184 WriteFile(FileHandle
, Hack
+ 1, 1, &NumberOfBytesWritten
, NULL
);
185 WriteFile(FileHandle
, Hack
, 1, &NumberOfBytesWritten
, NULL
);
194 char *MultiByteText
= new char[EditLength
* 4];
195 int MultiByteLength
= WideCharToMultiByte(CodePage
, 0, EditText
, EditLength
, MultiByteText
, EditLength
* 4, NULL
, NULL
);
196 WriteFile(FileHandle
, MultiByteText
, MultiByteLength
, &NumberOfBytesWritten
, NULL
);
197 delete[]MultiByteText
;
199 WriteFile(FileHandle
, EditText
, EditLength
, &NumberOfBytesWritten
, NULL
);
205 // The file handle is not closed here. We keep a write-lock on the file to stop other programs confusing us.
207 m_FilenameGUI
->SetDirty(false);
212 //void CEdit::TimeStampNewFiles(bool Value) {
213 // m_FilenameGUI->SetNewWithDate(Value);
217 switch (m_FilenameGUI
->QuerySaveFirst()) {
220 if(!TSaveAs(m_FilenameGUI
->SaveAs()))
232 switch (m_FilenameGUI
->QuerySaveFirst()) {
235 if(!TSaveAs(m_FilenameGUI
->SaveAs()))
244 TOpen(m_FilenameGUI
->Open());
247 void CEdit::OpenAppendMode() {
248 switch (m_FilenameGUI
->QuerySaveFirst()) {
251 if(!TSaveAs(m_FilenameGUI
->SaveAs()))
260 TOpenAppendMode(m_FilenameGUI
->Open());
263 void CEdit::SaveAs() {
264 TSaveAs(m_FilenameGUI
->SaveAs());
267 std::string
CEdit::Import() {
269 wstring_to_UTF8string(m_FilenameGUI
->Open(), filename
);
273 void CEdit::SetDirty() {
275 m_FilenameGUI
->SetDirty(true);
278 void CEdit::TNew(const Tstring
&filename
) {
279 if(filename
== TEXT(""))
280 m_filename
= m_FilenameGUI
->New();
282 m_filename
= filename
;
283 if(FileHandle
!= INVALID_HANDLE_VALUE
)
284 CloseHandle(FileHandle
);
285 FileHandle
= INVALID_HANDLE_VALUE
;
289 // m_pDasherInterface->InvalidateContext(true);
292 bool CEdit::TOpen(const Tstring
&filename
) {
293 // Could try and detect unicode formats from BOMs like notepad.
294 // Could also base codepage on menu.
295 // Best thing is probably to trust any BOMs at the beginning of file, but otherwise
296 // to believe menu. Unicode files don't necessarily have BOMs, especially from Unix.
298 HANDLE TmpHandle
= CreateFile(filename
.c_str(), GENERIC_READ
| GENERIC_WRITE
,
299 FILE_SHARE_READ
, (LPSECURITY_ATTRIBUTES
) NULL
,
300 OPEN_EXISTING
, FILE_ATTRIBUTE_NORMAL
,
303 if(TmpHandle
== INVALID_HANDLE_VALUE
)
306 if(FileHandle
!= INVALID_HANDLE_VALUE
)
307 CloseHandle(FileHandle
);
308 FileHandle
= TmpHandle
;
309 m_filename
= filename
;
311 SetFilePointer(FileHandle
, NULL
, NULL
, FILE_BEGIN
);
313 DWORD filesize
= GetFileSize(FileHandle
, NULL
);
314 unsigned long amountread
;
316 char *filebuffer
= new char[filesize
];
318 // Just read in whole file as char* and cast later.
320 ReadFile(FileHandle
, filebuffer
, filesize
, &amountread
, NULL
);
323 text
= text
+ filebuffer
;
325 UTF8string_to_wstring(text
, inserttext
);
326 InsertText(inserttext
);
329 m_FilenameGUI
->SetFilename(m_filename
);
330 m_FilenameGUI
->SetDirty(false);
335 bool CEdit::TOpenAppendMode(const Tstring
&filename
) {
341 bool CEdit::TSaveAs(const Tstring
&filename
) {
342 HANDLE TmpHandle
= CreateFile(filename
.c_str(), GENERIC_READ
| GENERIC_WRITE
,
343 FILE_SHARE_READ
, (LPSECURITY_ATTRIBUTES
) NULL
,
344 CREATE_ALWAYS
, FILE_ATTRIBUTE_NORMAL
,
347 if(TmpHandle
== INVALID_HANDLE_VALUE
)
350 if(FileHandle
!= INVALID_HANDLE_VALUE
)
351 CloseHandle(FileHandle
);
352 FileHandle
= TmpHandle
;
354 m_filename
= filename
;
356 m_FilenameGUI
->SetFilename(m_filename
);
365 SendMessage(WM_CUT
, 0, 0);
370 SendMessage(WM_COPY
, 0, 0);
375 handle = GlobalAlloc(GMEM_MOVEABLE|GMEM_DDESHARE, sizeof(DWORD));
376 foo = (DWORD*) GlobalLock(handle);
377 *foo = MAKELCID(MAKELANGID(LANG_JAPANESE, SUBLANG_DEFAULT), SORT_DEFAULT);
378 GlobalUnlock(handle);
379 OpenClipboard(m_hwnd);
380 SetClipboardData(CF_LOCALE, handle);
386 void CEdit::CopyAll()
388 // One might think this would lead to flickering of selecting and
389 // unselecting. It doesn't seem to. Using the clipboard directly
390 // is fiddly, so this cheat is useful.
392 SendMessage(EM_GETSEL
, (LONG
) & start
, (LONG
) & finish
);
393 SendMessage(EM_SETSEL
, 0, -1);
394 SendMessage(WM_COPY
, 0, 0);
395 SendMessage(EM_SETSEL
, (LONG
) start
, (LONG
) finish
);
400 SendMessage(WM_PASTE
, 0, 0);
403 void CEdit::SelectAll()
405 SendMessage(EM_SETSEL
, 0, -1);
410 SendMessage(WM_SETTEXT
, 0, (LPARAM
) TEXT(""));
414 void CEdit::SetEncoding(Dasher::Opts::FileEncodingFormats Encoding
) {
415 m_Encoding
= Encoding
;
418 void CEdit::SetFont(string Name
, long Size
) {
426 UTF8string_to_wstring(Name
, FontName
);
431 DeleteObject(m_Font
);
433 m_Font
= GetCodePageFont(CodePage
, -Size
);
435 m_Font
= CreateFont(-Size
, 0, 0, 0, FW_DONTCARE
, FALSE
, FALSE
, FALSE
, DEFAULT_CHARSET
, OUT_DEFAULT_PRECIS
, CLIP_DEFAULT_PRECIS
, DEFAULT_QUALITY
, FF_DONTCARE
, FontName
.c_str()); // DEFAULT_CHARSET => font made just from Size and FontName
437 SendMessage(WM_SETFONT
, (WPARAM
) m_Font
, true);
440 #pragma message ( "CEdit::SetFot not implemented on WinCE")
446 void CEdit::SetInterface(Dasher::CDasherInterfaceBase
*DasherInterface
) {
447 m_pDasherInterface
= DasherInterface
;
449 // TODO: What on Earth is this doing here?
450 SetFont(m_FontName
, m_FontSize
);
453 void CEdit::write_to_file() {
454 // TODO: Reimplement if necessary
456 //const string & TrainFile = m_pDasherInterface->GetTrainFile();
457 //if(TrainFile == "")
459 //Tstring TTrainFile;
460 //UTF8string_to_wstring(TrainFile, TTrainFile);
462 //HANDLE hFile = CreateFile(TTrainFile.c_str(),
463 // GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
465 //if(hFile == INVALID_HANDLE_VALUE) {
466 // OutputDebugString(TEXT("Can not open file\n"));
469 // DWORD NumberOfBytesWritten;
470 // SetFilePointer(hFile, 0, NULL, FILE_END);
471 // for(unsigned int i = 0; i < m_Output.size(); i++) {
472 // WriteFile(hFile, &m_Output[i], 1, &NumberOfBytesWritten, NULL);
476 // CloseHandle(hFile);
480 void CEdit::get_new_context(string
&str
, int max
) {
481 // Currently all of the edit box up to the caret is copied
482 // and then a few characters taken from that.
483 // This is a bit silly, but works for now. IAM 2002/08
486 SendMessage(EM_GETSEL
, (LONG
) & iStart
, (LONG
) & iFinish
);
488 TCHAR
*tString
= new TCHAR
[iFinish
+ 1];
490 SendMessage(WM_GETTEXT
, (LONG
) (iStart
+ 1), (LONG
) tString
);
493 wstring_to_UTF8string(tString
, Wasteful
);
495 if(Wasteful
.size() > max
)
496 str
= Wasteful
.substr(Wasteful
.size() - max
, max
);
503 void CEdit::output(const std::string
&sText
) {
505 WinUTF8::UTF8string_to_wstring(sText
, String
);
509 if(m_pAppSettings
->GetLongParameter(APP_LP_STYLE
) == 2) {
510 const char *DisplayText
= sText
.c_str();
512 if(DisplayText
[0] == 0xd && DisplayText
[1] == 0xa) {
513 // Newline, so we want to fake an enter
514 fakekey
[0].type
= fakekey
[1].type
= INPUT_KEYBOARD
;
515 fakekey
[0].ki
.wVk
= fakekey
[1].ki
.wVk
= VK_RETURN
;
516 fakekey
[0].ki
.time
= fakekey
[1].ki
.time
= 0;
517 fakekey
[1].ki
.dwFlags
= KEYEVENTF_KEYUP
;
518 SendInput(2, fakekey
, sizeof(INPUT
));
521 for(std::wstring::iterator
it(String
.begin()); it
!= String
.end(); ++it
) {
522 fakekey
[0].type
= INPUT_KEYBOARD
;
524 fakekey
[0].ki
.dwFlags
= KEYEVENTF_KEYUP
;
526 fakekey
[0].ki
.dwFlags
= KEYEVENTF_UNICODE
;
528 fakekey
[0].ki
.wVk
= 0;
529 fakekey
[0].ki
.time
= NULL
;
530 fakekey
[0].ki
.wScan
= *it
;
531 SendInput(1, fakekey
, sizeof(INPUT
));
535 if(DisplayText
[0] == 0xd && DisplayText
[1] == 0xa) {
536 // Newline, so we want to fake an enter
537 SetFocus(targetwindow
);
538 keybd_event(VK_RETURN
, 0, NULL
, NULL
);
539 keybd_event(VK_RETURN
, 0, KEYEVENTF_KEYUP
, NULL
);
542 WinUTF8::UTF8string_to_wstring(DisplayText
, &character
, 1252);
543 TCHAR test
= character
[0];
544 SHORT outputvk
= VkKeyScan(char (character
[0]));
545 SetFocus(targetwindow
);
546 if(HIBYTE(outputvk
) && 6) {
547 keybd_event(VK_SHIFT
, 0, NULL
, NULL
);
548 keybd_event(LOBYTE(outputvk
), 0, NULL
, NULL
);
549 keybd_event(LOBYTE(outputvk
), 0, KEYEVENTF_KEYUP
, NULL
);
550 keybd_event(VK_SHIFT
, 0, KEYEVENTF_KEYUP
, NULL
);
553 keybd_event(LOBYTE(outputvk
), 0, NULL
, NULL
);
554 keybd_event(LOBYTE(outputvk
), 0, KEYEVENTF_KEYUP
, NULL
);
560 UTF8string_to_wstring(sText
, newchar
);
564 void CEdit::Move(int iDirection
, int iDist
) {
566 // Unfortunately there doesn't seem to be a sane way of obtaining the caret
567 // position (as opposed to the bounds of the selection), so we're just going
568 // to have to assume that the caret is at the end...
572 SendMessage(EM_GETSEL
, (WPARAM
)&iStart
, (LPARAM
)&iEnd
);
583 std::wstring strBufferText
;
585 if(iDirection
== EDIT_FORWARDS
) {
593 // Hmm... words are hard - this is a rough and ready approximation:
595 iNumChars
= SendMessage(WM_GETTEXTLENGTH
, 0, 0);
596 hMemHandle
= (HLOCAL
)SendMessage( EM_GETHANDLE
, 0, 0);
597 strBufferText
= std::wstring((WCHAR
*)LocalLock(hMemHandle
), iNumChars
);
598 LocalUnlock(hMemHandle
);
600 iEnd
= strBufferText
.find(' ', iEnd
+1);
602 iEnd
= iNumChars
+ 1;
608 /* iEndLine = SendMessage( EM_LINEFROMCHAR, (WPARAM)iEnd, 0);
609 iLineOffset = iEnd - SendMessage( EM_LINEINDEX, (WPARAM)iEndLine, 0);
610 iNumLines = SendMessage( EM_GETLINECOUNT, 0, 0);
611 if( iEndLine < iNumLines - 1) {
613 iLineStart = SendMessage( EM_LINEINDEX, (WPARAM)iEndLine, 0);
614 iLineLength = SendMessage( EM_LINELENGTH, (WPARAM)iEndLine, 0);
615 if( iLineOffset < iLineLength )
616 iEnd = iLineStart+iLineOffset;
618 iEnd = iLineStart+iLineLength;
620 else if(iEndLine == iNumLines - 1) {
621 // we're on the last line so go to end of file
622 iNumChars = SendMessage(WM_GETTEXTLENGTH, 0, 0);
623 iEnd = iNumChars + 1;
626 // Make it behave like the 'End' key, unless we're at the end of the current line.
627 // Then go down a line.
628 iEndLine
= SendMessage(EM_LINEFROMCHAR
, (WPARAM
)iEnd
, 0);
629 iEnd
= SendMessage(EM_LINEINDEX
, (WPARAM
)(iEndLine
+ 1), 0) - 1; // end of this line
630 if(iStart
==iEnd
) // we were already at the end so go down a line
631 iEnd
= SendMessage(EM_LINEINDEX
, (WPARAM
)(iEndLine
+ 2), 0) - 1;
635 iNumChars
= SendMessage(WM_GETTEXTLENGTH
, 0, 0);
636 iEnd
= iNumChars
+ 1;
649 iNumChars
= SendMessage(WM_GETTEXTLENGTH
, 0, 0);
650 hMemHandle
= (HLOCAL
)SendMessage(EM_GETHANDLE
, 0, 0);
651 strBufferText
= std::wstring((WCHAR
*)LocalLock(hMemHandle
), iNumChars
);
652 LocalUnlock(hMemHandle
);
655 iEnd
= strBufferText
.rfind(' ', iEnd
-2);
665 iStartLine = SendMessage(EM_LINEFROMCHAR, (WPARAM)iStart, 0);
666 iEndLine = SendMessage(EM_LINEFROMCHAR, (WPARAM)iEnd, 0);
667 iLineOffset = iEnd - SendMessage(EM_LINEINDEX, (WPARAM)iEndLine, 0);
670 else if( iStartLine == 0)
672 // we're on the first line so go to start of file...
676 iLineStart = SendMessage(EM_LINEINDEX, (WPARAM)iStartLine, 0);
677 iLineLength = SendMessage(EM_LINELENGTH, (WPARAM)iStartLine, 0);
678 if( iLineOffset < iLineLength )
679 iStart = iLineStart+iLineOffset;
681 iStart = iLineStart+iLineLength;
683 iEndLine
= SendMessage(EM_LINEFROMCHAR
, (WPARAM
)iEnd
, 0);
684 iEnd
= SendMessage(EM_LINEINDEX
, (WPARAM
)(iEndLine
), 0); // start of this line
685 if(iStart
==iEnd
) // we were already at the start so go up a line
686 iEnd
= SendMessage(EM_LINEINDEX
, (WPARAM
)(iEndLine
- 1), 0);
696 SendMessage(EM_SETSEL
, (WPARAM
)iStart
, (LPARAM
)iEnd
);
697 SendMessage(EM_SCROLLCARET
, 0, 0); //scroll the caret into view!
700 void CEdit::Delete(int iDirection
, int iDist
) {
711 std::wstring strBufferText
;
713 SendMessage(EM_GETSEL
, (WPARAM
)&iStart
, (LPARAM
)&iEnd
);
715 if(iDirection
== EDIT_FORWARDS
) {
721 iNumChars
= SendMessage(WM_GETTEXTLENGTH
, 0, 0);
722 hMemHandle
= (HLOCAL
)SendMessage(EM_GETHANDLE
, 0, 0);
723 strBufferText
= std::wstring((WCHAR
*)LocalLock(hMemHandle
), iNumChars
);
724 LocalUnlock(hMemHandle
);
726 iEnd
= strBufferText
.find(' ', iEnd
+1);
728 iEnd
= iNumChars
+ 1;
732 iEndLine = SendMessage(EM_LINEFROMCHAR, (WPARAM)iEnd, 0);
733 iLineOffset = iEnd - SendMessage(EM_LINEINDEX, (WPARAM)iEndLine, 0);
734 iNumLines = SendMessage(EM_GETLINECOUNT, 0, 0);
735 if( iEndLine < iNumLines - 1) {
737 iLineStart = SendMessage(EM_LINEINDEX, (WPARAM)iEndLine, 0);
738 iLineLength = SendMessage(EM_LINELENGTH, (WPARAM)iEndLine, 0);
739 if( iLineOffset < iLineLength )
740 iEnd = iLineStart+iLineOffset;
742 iEnd = iLineStart+iLineLength;
745 iEndLine
= SendMessage(EM_LINEFROMCHAR
, (WPARAM
)iEnd
, 0);
746 iEnd
= SendMessage(EM_LINEINDEX
, (WPARAM
)(iEndLine
+ 1), 0); // end of this line
747 if(iStart
==iEnd
) // we were already at the end so go down a line
748 iEnd
= SendMessage(EM_LINEINDEX
, (WPARAM
)(iEndLine
+ 2), 0);
751 iNumChars
= SendMessage(WM_GETTEXTLENGTH
, 0, 0);
752 iEnd
= iNumChars
+ 1;
762 iNumChars
= SendMessage(WM_GETTEXTLENGTH
, 0, 0);
763 hMemHandle
= (HLOCAL
)SendMessage(EM_GETHANDLE
, 0, 0);
764 strBufferText
= std::wstring((WCHAR
*)LocalLock(hMemHandle
), iNumChars
);
765 LocalUnlock(hMemHandle
);
768 iEnd
= strBufferText
.rfind(' ', iEnd
-2);
776 /* iEndLine = SendMessage(EM_LINEFROMCHAR, (WPARAM)iEnd, 0);
777 iLineOffset = iEnd - SendMessage(EM_LINEINDEX, (WPARAM)iEndLine, 0);
778 iNumLines = SendMessage(EM_GETLINECOUNT, 0, 0);
781 iLineStart = SendMessage(EM_LINEINDEX, (WPARAM)iEndLine, 0);
782 iLineLength = SendMessage(EM_LINELENGTH, (WPARAM)iEndLine, 0);
783 if( iLineOffset < iLineLength )
784 iEnd = iLineStart+iLineOffset;
786 iEnd = iLineStart+iLineLength;
789 iEndLine
= SendMessage(EM_LINEFROMCHAR
, (WPARAM
)iEnd
, 0);
790 iEnd
= SendMessage(EM_LINEINDEX
, (WPARAM
)(iEndLine
), 0); // start of this line
791 if(iStart
==iEnd
) // we were already at the start so go up a line
792 iEnd
= SendMessage(EM_LINEINDEX
, (WPARAM
)(iEndLine
- 1), 0);
801 SendMessage(EM_SETSEL
, (WPARAM
)iStart
, (LPARAM
)iEnd
);
802 SendMessage(EM_REPLACESEL
, (WPARAM
)true, (LPARAM
)"");
805 /////////////////////////////////////////////////////////////////////////////
807 void CEdit::SetKeyboardTarget(HWND hwnd
)
809 m_bForwardKeyboard
= true;
813 /////////////////////////////////////////////////////////////////////////////
815 LRESULT
CEdit::OnLButtonDown(UINT message
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
817 m_bForwardKeyboard
= false;
818 bHandled
= FALSE
; // let the EDIT class handle it
822 /////////////////////////////////////////////////////////////////////////////
824 LRESULT
CEdit::OnLButtonUp(UINT message
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
826 // m_pDasherInterface->InvalidateContext(false);
828 bHandled
= FALSE
; // let the EDIT class handle it
832 /////////////////////////////////////////////////////////////////////////////
834 HRESULT
CEdit::OnChar(UINT message
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
836 if(!m_bForwardKeyboard
)
837 bHandled
= FALSE
; // let the EDIT class handle it
839 bHandled
= TRUE
; // traps the message, preventing it from reaching the EDIT control
844 /////////////////////////////////////////////////////////////////////////////
846 HRESULT
CEdit::OnKeyDown(UINT message
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
848 if(m_bForwardKeyboard
)
850 SendMessage(m_hTarget
,message
,wParam
,lParam
);
851 bHandled
= TRUE
; // traps the message, preventing it from reaching the EDIT control
854 bHandled
= FALSE
; // let the EDIT class handle it
858 /////////////////////////////////////////////////////////////////////////////
860 HRESULT
CEdit::OnKeyUp(UINT message
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
862 if(m_bForwardKeyboard
)
864 SendMessage(m_hTarget
,message
,wParam
,lParam
);
865 bHandled
= TRUE
; // traps the message, preventing it from reaching the EDIT control
869 // if we enter text or move around the edit control, update the Dasher display
870 //if (Canvas->Running()==false) { // FIXME - reimplement this
871 // m_pDasherInterface->ChangeEdit();
873 InvalidateRect(NULL
, FALSE
);
874 bHandled
= FALSE
; // let the EDIT class handle it
879 /////////////////////////////////////////////////////////////////////////////
881 HRESULT
CEdit::OnCommand(UINT message
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
884 return SendMessage( GetParent() , message
, wParam
, lParam
);
887 /////////////////////////////////////////////////////////////////////////////
889 void CEdit::InsertText(Tstring InsertText
) {
890 SendMessage(EM_REPLACESEL
, TRUE
, (LPARAM
) InsertText
.c_str());
893 // TODO The following were inline in DJW's code. Think about reinstating
896 void CEdit::dumpedit(int i) const
900 wsprintf(deb,TEXT("edit %d %x\n"),i,m_hwnd);
901 OutputDebugString(deb);
905 /// Delete text from the editbox
907 void CEdit::deletetext(const std::string
&sText
) {
908 // Lookup the unicode string that we need to delete - we only actually
909 // need the length of the string, but this is important eg for newline
910 // characters which are actually two symbols
913 WinUTF8::UTF8string_to_wstring(sText
, String
);
915 int iLength(String
.size());
917 // Get the start and end of the current selection, and decrement the start
918 // by the number of characters to be deleted
921 SendMessage(EM_GETSEL
, (LONG
) & start
, (LONG
) & finish
);
923 SendMessage(EM_SETSEL
, (LONG
) start
, (LONG
) finish
);
925 // Replace the selection with a null string
928 wsprintf(out
, TEXT(""));
929 SendMessage(EM_REPLACESEL
, TRUE
, (LONG
) out
);
931 // FIXME - I *think* we still only want to send one keyboard event to delete a
932 // newline pair, but we're now assuming we'll never have two real characters for
935 // if(targetwindow != NULL && textentry == true) {
936 if(m_pAppSettings
->GetLongParameter(APP_LP_STYLE
) == 2) {
939 fakekey
[0].type
= fakekey
[1].type
= INPUT_KEYBOARD
;
940 fakekey
[0].ki
.wVk
= fakekey
[1].ki
.wVk
= VK_BACK
;
941 fakekey
[0].ki
.time
= fakekey
[1].ki
.time
= 0;
942 fakekey
[1].ki
.dwFlags
= KEYEVENTF_KEYUP
;
944 ::SetFocus(targetwindow
);
945 SendInput(2, fakekey
, sizeof(INPUT
));
947 SetFocus(targetwindow
);
948 keybd_event(VK_BACK
, 0, NULL
, NULL
);
949 keybd_event(VK_BACK
, 0, KEYEVENTF_KEYUP
, NULL
);
953 // Shorten the speech buffer (?)
954 if(speech
.length() >= iLength
) {
955 speech
.resize(speech
.length() - iLength
);
958 // And the output buffer (?)
959 if(m_Output
.length() >= iLength
) {
960 m_Output
.resize(m_Output
.length() - iLength
);
964 //void CEdit::SetWindow(HWND window)
967 //#ifndef DASHER_WINCE
969 // if(targetwindow != window) {
971 // targetwindow = window;
973 // if(threadid != NULL) {
975 // AttachThreadInput(GetCurrentThreadId(), threadid, FALSE);
977 // // SetFocus(Parent);
981 // if(window != NULL) {
983 // threadid = GetWindowThreadProcessId(window, NULL);
985 // AttachThreadInput(GetCurrentThreadId(), GetWindowThreadProcessId(window, NULL), TRUE);
987 // // SetFocus(window);
998 void CEdit::speak(int what
) {
999 if(!m_pActionSpeech
->GetActive())
1002 // TODO: The remainder of this function is somewhat horrible and hacky...
1004 // TODO: Horrible hack - don't speak in direct entry mode
1005 if(m_pAppSettings
->GetLongParameter(APP_LP_STYLE
) == 2)
1008 std::wstring strSpeech
;
1010 if(what
== 1) { // All
1011 int speechlength
= GetWindowTextLength();
1012 LPTSTR allspeech
= new TCHAR
[speechlength
+ 1];
1013 GetWindowText(allspeech
, speechlength
+ 1);
1014 strSpeech
= allspeech
;
1015 lastspeech
= allspeech
;
1019 else if(what
== 2) { // New
1021 lastspeech
= speech
;
1024 else if(what
== 3) {
1025 strSpeech
= lastspeech
;
1028 m_pActionSpeech
->Execue(strSpeech
);
1031 void CEdit::SetNewWithDate(bool bNewWithDate
) {
1033 m_FilenameGUI
->SetNewWithDate(bNewWithDate
);
1037 void CEdit::HandleEvent(Dasher::CEvent
*pEvent
) {
1038 // TODO: Note the mess in the parent class which ulitmately results in this being called - sort it out sometime
1040 switch(pEvent
->m_iEventType
) {
1042 HandleEditEvent(pEvent
);
1050 void CEdit::HandleEditEvent(Dasher::CEvent
*pEvent
) {
1051 Dasher::CEditEvent
* pEvt(static_cast< Dasher::CEditEvent
* >(pEvent
));
1053 switch (pEvt
->m_iEditType
) {
1055 output(pEvt
->m_sText
);
1058 deletetext(pEvt
->m_sText
);
1063 void CEdit::HandleStop() {
1064 if(m_pAppSettings
->GetBoolParameter(APP_BP_SPEECH_MODE
))
1067 if(m_pAppSettings
->GetBoolParameter(APP_BP_COPY_ALL_ON_STOP
))