by yu0627 » 2006年4月07日(金) 14:33
こんにちは。yu0627です。
今のところ、以下のところまで来ました。
○日本語入力への対応
→とりやえず実装。ただし二文字以上でゴミが入る。
○BackSpaceとDeleteへの対応
→とりあえず実装。ただし日本語入力で文字化けしたり、ゴミが入る。
また、英字でゴミが入る。
○切り取りへの対応
→暫定実装。データが大きいサイズを処理するとバグが出る
○貼り付けへの対応
→実装。まだ改良余地あり
○REDOへの対応
→未実装
○その他
・UNDO後のpNewNextポインタの開放でHEAPが起きる
追記:BackSpace、Deleteキーの英字のごみ問題は解決しました。
しかし、Edit上で日本語と英字のサイズは同じなのに変数上で1バイトと2バイトに分かれるので難しいです。
以下がコードです。
リッチエディット仕様に書き換えてある箇所もあるので、そちらでなんとかしてください(爆)
リッチエディットのハンドル:hEdit
あと、「SetKeywordColor」はコメントアウトで。
[ここをクリックすると内容が表示されます] [ここをクリックすると非表示にします]コード: 全て選択
Dim pOldEditProc As VoidPtr
Dim pUndo As *Undo
Dim IMEStartCharIndex As CHARRANGE '変換が始まるときのカーソルの位置
'Dim pRedo As *Redo
Const UNDO_INPUT = 0 '文字を入力した時 現状アルファベット、数字のみ対応
Const UNDO_DELETE = 1 'Deleteキーを押した時
Const UNDO_BACK =2 'BackSpaceキーを押した時 Deleteとカーソル位置が同じでも削除の方向が異なる
Const UNDO_PASTE = 3 'ペーストした時 UNDO_INPUTと同じでもよさそう
Const UNDO_CUT = 4 '切り取りした時
Const UNDO_COLORCUT = 5 'リッチテキスト形式で切り取りする時
Const UNDO_KANJIINPUT = 6 '日本語変換有効時
Type UNDO
pNext As *UNDO
nType As Long
nStart As Long
szText As String
nLength As Long
End Type
/*
Type REDO
pNext As *REDO
nType As Long
nStart As Long
szText As String
nLength As Long
End Type
*/
Function CreateUndoBuffer() As *Undo
CreateUndoBuffer=malloc(20)
CreateUndoBuffer->pNext=0
End Function
Sub DestroyUndoBuffer(pBuffer As *Undo)
Dim p As *Undo
While pBuffer->pNext
p=pBuffer->pNext
free(pBuffer)
pBuffer=p
Wend
End Sub
/*
Function CreateRedoBuffer() As *Redo
CreateRedoBuffer=malloc(20)
CreateRedoBuffer->pNext=0
End Function
Sub DestroyRedoBuffer(pBuffer As *Redo)
Dim p As *Redo
While pBuffer->pNext
p=pBuffer->pNext
free(pBuffer)
pBuffer=p
Wend
End Sub
*/
'アンドゥバッファに追加する
'現在入力時しかないのでまだまだ改良の余地あり? 引数とか
Sub AddUndo(nType As Long,nStart As Long,pszText As BytePtr,nLength As Long) As *UNDO
Dim ptmp As *UNDO
ptmp=pUndo
pUndo=malloc(20)'Len(ptmp)とかLen(UNDO)ができないので数値直指定 UNDO構造体変更時はここ注意
pUndo->pNext=ptmp
pUndo->nType=nType
pUndo->nStart=nStart
pUndo->szText=pszText
pUndo->nLength=nLength
End Sub
'アンドゥを実行する
Sub CallUndo()
'アンドゥバッファが空の場合関数を抜ける
If pUndo->pNext=0 Then Exit Sub
Dim pNowText As BytePtr'現在のテキスト
Dim pNewText As BytePtr'新しく設定するテキスト
Dim chrg As CHARRANGE
Dim dwStartChar As DWord
Dim dwEndChar As DWord
Dim Length As Long'テキストの長さなんか
Dim ptmp As *UNDO'pUndoの一時保管
Dim strBuffer As String
SendMessage(hEdit, EM_EXGETSEL, 0, VarPtr(chrg))
dwStartChar=chrg.cpMin
'##### 現在のテキスト取得 始まり #####
Length=GetWindowTextLength(hEdit)+1
pNowText=malloc(Length)
GetWindowText(hEdit, pNowText, Length)
'##### 現在のテキスト取得 終わり #####
Select Case pUndo->nType
Case UNDO_INPUT
'##### アンドゥ後のテキストの長さ #####
Length=Length-pUndo->nLength+lstrlen(pUndo->szText)
'##### アンドゥ後のバッファ確保 #####
'MoveMemory使うからcallocで確保する
pNewText=calloc(Length+1)
'##### 先頭からカーソルまでをコピー #####
MoveMemory(pNewText, pNowText, pUndo->nStart)
'##### 入力時に消された文字を追加する #####
'文字選択状態で文字入力した時の為
lstrcat(pNewText,StrPtr(pUndo->szText))
'##### カーソルから最後までをコピー #####
lstrcat(pNewText,pNowText+pUndo->nStart+pUndo->nLength)
'##### 新しいバッファを設定 #####
SetWindowText(hEdit,pNewText)
'##### カーソルを元の位置に戻す #####
SendMessage(hEdit,EM_SETSEL,pUndo->nStart,pUndo->nStart)
Case UNDO_BACK
'##### アンドゥ後のテキストの長さ #####
Length=Length+Len(pUndo->szText)
'##### アンドゥ後のバッファ確保 #####
'MoveMemory使うからcallocで確保する
pNewText=calloc(Length+1)
'##### 先頭からカーソルまでをコピー #####
If IsDBCSLeadByte(pNowText[pUndo->nStart]) Then
MoveMemory(pNewText, pNowText, pUndo->nStart+1)
Else
MoveMemory(pNewText, pNowText, pUndo->nStart)
End If
'BackSpaceで消された文字をコピー
lstrcat(pNewText, StrPtr(pUndo->szText))
'##### カーソルから最後までをコピー #####
If lstrlen(pNewText)<>Length-1 Then
lstrcat(pNewText, pNowText+pUndo->nStart+pUndo->nLength)
End If
'##### 新しいバッファを設定 #####
SetWindowText(hEdit, pNewText)
'##### カーソルを元の位置に戻す #####
If pUndo->nLength=1 or pUndo->nLength=2 Then
SendMessage(hEdit, EM_SETSEL, pUndo->nStart+1, pUndo->nStart+1)
Else
SendMessage(hEdit, EM_SETSEL, pUndo->nStart+pUndo->nLength+1, pUndo->nStart->+pUndo->nLength+1)
End If
Case UNDO_DELETE
'##### アンドゥ後のテキストの長さ #####
Length=Length+pUndo->nLength
'##### アンドゥ後のバッファ確保 #####
'MoveMemory使うからcallocで確保する
pNewText=calloc(Length+1)
'##### 先頭からカーソルまでをコピー #####
MoveMemory(pNewText, pNowText, pUndo->nStart)
'##### 入力時に消された文字を追加する #####
'文字選択状態で文字入力した時の為
lstrcat(pNewText, StrPtr(pUndo->szText))
'##### カーソルから最後までをコピー #####
If lstrlen(pNewText)<>Length-1 Then
lstrcat(pNewText, pNowText+pUndo->nStart+pUndo->nLength)
End If
'##### 新しいバッファを設定 #####
SetWindowText(hEdit, pNewText)
'##### カーソルを元の位置に戻す #####
SendMessage(hEdit, EM_SETSEL, pUndo->nStart, pUndo->nStart) Case UNDO_PASTE
LockWindowUpdate(hEdit)
'貼り付けられた範囲を選択する
chrg.cpMin=pUndo->nStart
chrg.cpMax=pUndo->nStart+pUndo->nLength
SendMessage(hEdit, EM_EXSETSEL, 0, VarPtr(chrg))
'選択した範囲を上書きされた文字列で上書きする
SendMessage(hEdit, EM_REPLACESEL, 0, pUndo->szText)
'カーソルを元の位置に戻す
SendMessage(hEdit,EM_SETSEL,pUndo->nStart,pUndo->nStart)
LockWindowUpdate(NULL)
Case UNDO_CUT
'nStartで指定された位置に文字を挿入
chrg.cpMin=pUndo->nStart
SendMessage(hEdit, EM_REPLACESEL, 0, pUndo->szText)
Case UNDO_COLORCUT
'nStartで指定された位置に文字を挿入
chrg.cpMin=pUndo->nStart
SendMessage(hEdit, EM_REPLACESEL, 0, pUndo->szText)
Case UNDO_KANJIINPUT
'##### アンドゥ後のテキストの長さ #####
Length=Length-pUndo->nLength+Len(pUndo->szText)
'##### アンドゥ後のバッファ確保 #####
'MoveMemory使うからcallocで確保する
pNewText=calloc(Length+1)
'##### 先頭からカーソルまでをコピー #####
MoveMemory(pNewText, pNowText, pUndo->nStart)
'##### 入力時に消された文字を追加する #####
'文字選択状態で文字入力した時の為
lstrcat(pNewText, StrPtr(pUndo->szText))
'##### カーソルから最後までをコピー #####
lstrcat(pNewText, pNowText+pUndo->nStart+pUndo->nLength+1)
'##### 新しいバッファを設定 #####
SetWindowText(hEdit, pNewText)
'##### カーソルを元の位置に戻す #####
SendMessage(hEdit, EM_SETSEL, pUndo->nStart, pUndo->nStart)
End Select
'##### 一番新しいアンドゥバッファを削除する 始まり #####
ptmp=pUndo->pNext
free(pUndo)'リドゥにも対応する場合はfreeせずにリドゥバッファに渡す(リドゥバッファを新たに作成する必要あり)
pUndo=ptmp
'##### 一番新しいアンドゥバッファを削除する 終わり #####
'##### 後始末 #####
SendMessage(hEdit, EM_EXGETSEL, 0, VarPtr(chrg))
MainWnd_IDM_REDRAW_MenuClick()
If pNowText Then free(pNowText)
If pNewText Then free(pNewText)
End Sub
'クリップボードからテキストデータを貼り付ける
Sub CallPaste()
Dim chrg As CHARRANGE
Dim pszPasteText As BytePtr
Dim lpszPasteText As BytePtr
Dim dwlength As DWord
Dim lpszbuf As BytePtr, lpszbuf2 As BytePtr
Dim dwEvent As DWord
If SendMessage(hEdit, EM_CANPASTE, 0, 0) Then
'クリップボードをオープンする
If OpenClipboard(NULL)=FALSE Then
MessageBox(hMainWnd, "クリップボードのオープンに失敗", "Error", MB_OK or MB_ICONSTOP)
Exit Sub
End If
'クリップボードの内容を読み取る
pszPasteText=GetClipboardData(CF_TEXT)
If pszPasteText=NULL Then Exit Sub
'クリップボードの内容を他の変数にコピー
lpszPasteText=malloc(lstrlen(pszPasteText)+1)
lstrcpy(lpszPasteText, pszPasteText)
'クリップボードを閉じる
CloseClipboard()
'---ここからアンドゥ関係処理---
'カーソルの位置を取得し、サイズを計算してバッファを確保
SendMessage(hEdit, EM_EXGETSEL, 0, VarPtr(chrg))
dwlength=chrg.cpMax-chrg.cpMin
lpszbuf=malloc(GetWindowTextLength(hEdit)+1)
lpszbuf2=calloc(dwlength+1)
'現在のテキストを取得
GetWindowText(hEdit, lpszbuf, GetWindowTextLength(hEdit)+1)
'選択文字を取得
MoveMemory(lpszbuf2, lpszbuf+chrg.cpMin, dwlength)
'アンドゥに追加
AddUndo(UNDO_PASTE, chrg.cpMin, lpszbuf2, lstrlen(lpszPasteText)+1)
'---ここまで---
'クリップボードの内容をhEditに挿入
SendMessage(hEdit, EM_REPLACESEL, 0, lpszPasteText)
'イベントマスクからENM_CHANGEをはずす
dwEvent=SendMessage(hEdit, EM_GETEVENTMASK, 0, 0)
SendMessage(hEdit, EM_SETEVENTMASK, 0, dwEvent xor ENM_CHANGE)
'文字色を変更する
SetKeywordColor(0, -1)
'イベントマスクにENM_CHANGEを追加する
dwEvent=SendMessage(hEdit, EM_GETEVENTMASK, 0, 0)
SendMessage(hEdit, EM_SETEVENTMASK, 0, dwEvent or ENM_CHANGE)
'後処理
free(lpszPasteText)
free(lpszbuf)
free(lpszbuf2)
End If
End Sub
Sub CallCut()
Dim chrg As CHARRANGE
Dim pszCutText As BytePtr
Dim hGlobalMem As DWord
Dim dwCutTextLength As DWord
Dim length As DWord
Dim buf As BytePtr
Dim buf2 As BytePtr
SendMessage(hEdit, EM_EXGETSEL, 0, VarPtr(chrg))
If chrg.cpMin<>chrg.cpMax Then
'クリップボードをオープンする
If OpenClipboard(NULL)=FALSE Then
MessageBox(hMainWnd, "クリップボードのオープンに失敗", "Error", MB_OK or MB_ICONSTOP)
Exit Sub
End If
'クリップボードを空にする
EmptyClipboard()
'クリップボードに選択された文字列をコピーする
dwCutTextLength=GetWindowTextLength(hEdit)
hGlobalMem=GlobalAlloc(GHND or GMEM_SHARE, dwCutTextLength+1)
pszCutText=GlobalLock(hGlobalMem)
If pszCutText=NULL Then
MessageBox(hMainWnd, "クリックボードにコピーするテキスト用のバッファ確保取得に失敗", "Error ", MB_OK or MB_ICONSTOP)
Exit Sub
End If
SendMessage(hEdit, EM_GETSELTEXT, 0, pszCutText)
GlobalUnlock(hGlobalMem)
SetClipboardData(CF_TEXT, hGlobalMem)
CloseClipboard()
'---ここからアンドゥ関係処理---
'バッファを確保
length=chrg.cpMax-chrg.cpMin
buf=malloc(GetWindowTextLength(hEdit)+1)
buf2=calloc(length+1)
'現在のテキストを取得
GetWindowText(hEdit, buf, GetWindowTextLength(hEdit)+1)
'切り取られる部分の文字を取得
SendMessage(hEdit, EM_GETSELTEXT, 0, buf2)
'アンドゥ追加
AddUndo(UNDO_CUT, chrg.cpMin, buf2, Len(buf2))
'---ここまで---
'選択された範囲を無文字に置換する
SendMessage(hEdit, EM_REPLACESEL, 0, "")
'後処理
free(buf)
free(buf2)
End If
End Sub
Sub CallColorCut()
Dim chrg As CHARRANGE
Dim pszCutText As BytePtr
Dim hGlobalMem As DWord
Dim dwCutTextLength As DWord
Dim length As DWord
Dim buf As BytePtr
Dim buf2 As BytePtr
SendMessage(hEdit, EM_EXGETSEL, 0, VarPtr(chrg))
If chrg.cpMin<>chrg.cpMax Then
'---ここからアンドゥ関係処理---
'バッファを確保
length=chrg.cpMax-chrg.cpMin
buf=malloc(GetWindowTextLength(hEdit)+1)
buf2=calloc(length+1)
'現在のテキストを取得
GetWindowText(hEdit, buf, GetWindowTextLength(hEdit)+1)
'切り取られる部分文字を取得
SendMessage(hEdit, EM_GETSELTEXT, 0, buf2)
'アンドゥ追加
AddUndo(UNDO_COLORCUT, chrg.cpMin, buf2, Len(buf2))
'---ここまで---
SendMessage(hEdit, WM_CUT, 0, 0)
'後処理
free(buf)
free(buf2)
End If
End Sub
Sub CallAllSelect()
Dim chrg As CHARRANGE
chrg.cpMax=-1
SendMessage(hEdit, EM_EXSETSEL, 0, VarPtr(chrg))
End Sub
Function EditProc(hWnd As HWND,message As DWord,wParam As WPARAM,lParam As LPARAM) As LRESULT
Dim nStart As Long, nEnd As Long, length As Long
Dim buf As BytePtr, buf2 As BytePtr, buf3 As BytePtr
Dim chrg As CHARRANGE
If Not (GetAsyncKeyState(VK_CONTROL) and &H8000) Then
Select Case message
Case WM_IME_STARTCOMPOSITION
'カーソル位置を取得
SendMessage(hEdit, EM_EXGETSEL, 0, VarPtr(chrg))
IMEStartCharIndex.cpMin=chrg.cpMin
IMEStartCharIndex.cpMax=chrg.cpMax
Case WM_IME_ENDCOMPOSITION
'カーソル位置を取得
SendMessage(hEdit, EM_EXGETSEL, 0, VarPtr(chrg))
If IMEStartCharIndex.cpMin<>chrg.cpMin Then
If IMEStartCharIndex.cpMin<>IMEStartCharIndex.cpMax Then
length=chrg.cpMax-IMEStartCharIndex.cpMin
buf2=malloc(GetWindowTextLength(hEdit)+1)
SendMessage(hEdit, EM_GETSELTEXT, 0, buf2)
AddUndo(UNDO_KANJIINPUT, IMEStartCharIndex.cpMin, buf2, length)
Else
length=chrg.cpMax-IMEStartCharIndex.cpMin
buf2=malloc(length+1)
lstrcpy(buf2, "")
AddUndo(UNDO_KANJIINPUT, IMEStartCharIndex.cpMin, buf2, length)
End If
End If
Case WM_UNDO
'EDITの本来のアンドゥ処理をさせない
Exit Function
Case WM_PASTE
Exit Function
Case WM_KEYDOWN
If wParam=Asc("Z") and (GetAsyncKeyState(VK_CONTROL) and &H8000) Then
'Control+Zが押された
'自前のアンドゥを行う
CallUndo()
Exit Function
ElseIf wParam=Asc("V") and (GetAsyncKeyState(VK_CONTROL) and &H8000) Then
CallPaste()
Exit Function
ElseIf wParam=Asc("A") and (GetAsyncKeyState(VK_CONTROL) and &H8000) Then
CallAllSelect()
Exit Function
ElseIf wParam>=Asc("A") and wParam<=Asc("Z") or wParam>=Asc("0") and wParam<=Asc("9") or _
(wParam>=VK_NUMPAD0 and wParam<=VK_DIVIDE xor wParam=VK_SEPARATOR) Then
'入力が数字の0~9、アルファベットのA~Zの場合
'IME ONや、上書きモードは考慮されていません
'カーソル位置を取得
SendMessage(hEdit, EM_EXGETSEL, 0, VarPtr(chrg))
'##### 選択バイト数 #####
length=chrg.cpMax-chrg.cpMin
'##### 現在のテキストバッファを確保 #####
buf=malloc(GetWindowTextLength(hEdit)+1)
'##### 選択文字のバッファを確保 #####
buf2=calloc(length+1)
'##### 現在のテキスト取得 #####
GetWindowText(hEdit, buf, GetWindowTextLength(hEdit)+1)
'##### 選択文字取得 #####
MoveMemory(buf2, buf+chrg.cpMin, length)
'##### アンドゥ追加 #####
AddUndo(UNDO_INPUT, chrg.cpMin, buf2, 1)
ElseIf wParam=VK_BACK Then
'ユーザーがBackSpaceキーを押したとき
'カーソル位置を取得
SendMessage(hEdit, EM_EXGETSEL, 0, VarPtr(chrg))
'バッファを確保
length=chrg.cpMax-chrg.cpMin
buf=malloc(GetWindowTextLength(hEdit)+1)
buf2=calloc(length+1)
If chrg.cpMax=0 Then goto *EditProcEnd
If chrg.cpMin<>chrg.cpMax Then
'除去される部分文字を取得
SendMessage(hEdit, EM_GETSELTEXT, 0, buf2)
'アンドゥ追加
AddUndo(UNDO_BACK, chrg.cpMax, buf2, Len(buf2))
Else
length=1
buf2=calloc(length+1)
buf3=calloc(3)
'現在のテキストを取得
GetWindowText(hEdit, buf, GetWindowTextLength(hEdit)+1)
'除去される文字を取得
MoveMemory(buf2, buf+chrg.cpMin-1, length)
MoveMemory(buf3, buf+chrg.cpMin-1, 2)
If IsDBCSLeadByte(buf3[0]) Then
'日本語用アンドゥ追加
AddUndo(UNDO_BACK, chrg.cpMin, buf3, 2)
free(buf3)
Else
'アンドゥ追加
AddUndo(UNDO_BACK, chrg.cpMin, buf2, length)
End If
End If
ElseIf wParam=VK_DELETE Then
'ユーザーがDeleteキーを押したとき
'カーソル位置を取得
SendMessage(hEdit, EM_EXGETSEL, 0, VarPtr(chrg))
'バッファを確保
length=chrg.cpMax-chrg.cpMin
buf=malloc(GetWindowTextLength(hEdit)+1)
buf2=calloc(length+1)
If chrg.cpMin<>chrg.cpMax Then
'除去される部分文字を取得
SendMessage(hEdit, EM_GETSELTEXT, 0, buf2)
'アンドゥ追加
AddUndo(UNDO_DELETE, chrg.cpMax, buf2, Len(buf2))
Else
If GetWindowTextLength(hEdit)=chrg.cpMin Then goto *EditProcEnd
length=1
buf2=calloc(length+1)
buf3=calloc(3)
'現在のテキストを取得
GetWindowText(hEdit, buf, GetWindowTextLength(hEdit)+1)
'除去される文字を取得
MoveMemory(buf2, buf+chrg.cpMin, length)
MoveMemory(buf3, buf+chrg.cpMin, 2)
Debug
If IsDBCSLeadByte(buf3[0]) Then
'日本語用アンドゥ追加
AddUndo(UNDO_BACK, chrg.cpMin, buf3, 2)
free(buf3)
Else
'アンドゥ追加
AddUndo(UNDO_BACK, chrg.cpMin, buf2, length)
End If
End If
End If
End Select
End If
*EditProcEnd
EditProc=CallWindowProc(pOldEditProc,hWnd,message,wParam,lParam)
free(buf)
free(buf2)
End Function
大変...。
こんにちは。yu0627です。
今のところ、以下のところまで来ました。
○日本語入力への対応
→とりやえず実装。ただし二文字以上でゴミが入る。
○BackSpaceとDeleteへの対応
→とりあえず実装。ただし日本語入力で文字化けしたり、ゴミが入る。
また、英字でゴミが入る。
○切り取りへの対応
→暫定実装。データが大きいサイズを処理するとバグが出る
○貼り付けへの対応
→実装。まだ改良余地あり
○REDOへの対応
→未実装
○その他
・UNDO後のpNewNextポインタの開放でHEAPが起きる
追記:BackSpace、Deleteキーの英字のごみ問題は解決しました。
しかし、Edit上で日本語と英字のサイズは同じなのに変数上で1バイトと2バイトに分かれるので難しいです。
以下がコードです。
リッチエディット仕様に書き換えてある箇所もあるので、そちらでなんとかしてください(爆)
リッチエディットのハンドル:hEdit
あと、「SetKeywordColor」はコメントアウトで。
[hide][code]Dim pOldEditProc As VoidPtr
Dim pUndo As *Undo
Dim IMEStartCharIndex As CHARRANGE '変換が始まるときのカーソルの位置
'Dim pRedo As *Redo
Const UNDO_INPUT = 0 '文字を入力した時 現状アルファベット、数字のみ対応
Const UNDO_DELETE = 1 'Deleteキーを押した時
Const UNDO_BACK =2 'BackSpaceキーを押した時 Deleteとカーソル位置が同じでも削除の方向が異なる
Const UNDO_PASTE = 3 'ペーストした時 UNDO_INPUTと同じでもよさそう
Const UNDO_CUT = 4 '切り取りした時
Const UNDO_COLORCUT = 5 'リッチテキスト形式で切り取りする時
Const UNDO_KANJIINPUT = 6 '日本語変換有効時
Type UNDO
pNext As *UNDO
nType As Long
nStart As Long
szText As String
nLength As Long
End Type
/*
Type REDO
pNext As *REDO
nType As Long
nStart As Long
szText As String
nLength As Long
End Type
*/
Function CreateUndoBuffer() As *Undo
CreateUndoBuffer=malloc(20)
CreateUndoBuffer->pNext=0
End Function
Sub DestroyUndoBuffer(pBuffer As *Undo)
Dim p As *Undo
While pBuffer->pNext
p=pBuffer->pNext
free(pBuffer)
pBuffer=p
Wend
End Sub
/*
Function CreateRedoBuffer() As *Redo
CreateRedoBuffer=malloc(20)
CreateRedoBuffer->pNext=0
End Function
Sub DestroyRedoBuffer(pBuffer As *Redo)
Dim p As *Redo
While pBuffer->pNext
p=pBuffer->pNext
free(pBuffer)
pBuffer=p
Wend
End Sub
*/
'アンドゥバッファに追加する
'現在入力時しかないのでまだまだ改良の余地あり? 引数とか
Sub AddUndo(nType As Long,nStart As Long,pszText As BytePtr,nLength As Long) As *UNDO
Dim ptmp As *UNDO
ptmp=pUndo
pUndo=malloc(20)'Len(ptmp)とかLen(UNDO)ができないので数値直指定 UNDO構造体変更時はここ注意
pUndo->pNext=ptmp
pUndo->nType=nType
pUndo->nStart=nStart
pUndo->szText=pszText
pUndo->nLength=nLength
End Sub
'アンドゥを実行する
Sub CallUndo()
'アンドゥバッファが空の場合関数を抜ける
If pUndo->pNext=0 Then Exit Sub
Dim pNowText As BytePtr'現在のテキスト
Dim pNewText As BytePtr'新しく設定するテキスト
Dim chrg As CHARRANGE
Dim dwStartChar As DWord
Dim dwEndChar As DWord
Dim Length As Long'テキストの長さなんか
Dim ptmp As *UNDO'pUndoの一時保管
Dim strBuffer As String
SendMessage(hEdit, EM_EXGETSEL, 0, VarPtr(chrg))
dwStartChar=chrg.cpMin
'##### 現在のテキスト取得 始まり #####
Length=GetWindowTextLength(hEdit)+1
pNowText=malloc(Length)
GetWindowText(hEdit, pNowText, Length)
'##### 現在のテキスト取得 終わり #####
Select Case pUndo->nType
Case UNDO_INPUT
'##### アンドゥ後のテキストの長さ #####
Length=Length-pUndo->nLength+lstrlen(pUndo->szText)
'##### アンドゥ後のバッファ確保 #####
'MoveMemory使うからcallocで確保する
pNewText=calloc(Length+1)
'##### 先頭からカーソルまでをコピー #####
MoveMemory(pNewText, pNowText, pUndo->nStart)
'##### 入力時に消された文字を追加する #####
'文字選択状態で文字入力した時の為
lstrcat(pNewText,StrPtr(pUndo->szText))
'##### カーソルから最後までをコピー #####
lstrcat(pNewText,pNowText+pUndo->nStart+pUndo->nLength)
'##### 新しいバッファを設定 #####
SetWindowText(hEdit,pNewText)
'##### カーソルを元の位置に戻す #####
SendMessage(hEdit,EM_SETSEL,pUndo->nStart,pUndo->nStart)
Case UNDO_BACK
'##### アンドゥ後のテキストの長さ #####
Length=Length+Len(pUndo->szText)
'##### アンドゥ後のバッファ確保 #####
'MoveMemory使うからcallocで確保する
pNewText=calloc(Length+1)
'##### 先頭からカーソルまでをコピー #####
If IsDBCSLeadByte(pNowText[pUndo->nStart]) Then
MoveMemory(pNewText, pNowText, pUndo->nStart+1)
Else
MoveMemory(pNewText, pNowText, pUndo->nStart)
End If
'BackSpaceで消された文字をコピー
lstrcat(pNewText, StrPtr(pUndo->szText))
'##### カーソルから最後までをコピー #####
If lstrlen(pNewText)<>Length-1 Then
lstrcat(pNewText, pNowText+pUndo->nStart+pUndo->nLength)
End If
'##### 新しいバッファを設定 #####
SetWindowText(hEdit, pNewText)
'##### カーソルを元の位置に戻す #####
If pUndo->nLength=1 or pUndo->nLength=2 Then
SendMessage(hEdit, EM_SETSEL, pUndo->nStart+1, pUndo->nStart+1)
Else
SendMessage(hEdit, EM_SETSEL, pUndo->nStart+pUndo->nLength+1, pUndo->nStart->+pUndo->nLength+1)
End If
Case UNDO_DELETE
'##### アンドゥ後のテキストの長さ #####
Length=Length+pUndo->nLength
'##### アンドゥ後のバッファ確保 #####
'MoveMemory使うからcallocで確保する
pNewText=calloc(Length+1)
'##### 先頭からカーソルまでをコピー #####
MoveMemory(pNewText, pNowText, pUndo->nStart)
'##### 入力時に消された文字を追加する #####
'文字選択状態で文字入力した時の為
lstrcat(pNewText, StrPtr(pUndo->szText))
'##### カーソルから最後までをコピー #####
If lstrlen(pNewText)<>Length-1 Then
lstrcat(pNewText, pNowText+pUndo->nStart+pUndo->nLength)
End If
'##### 新しいバッファを設定 #####
SetWindowText(hEdit, pNewText)
'##### カーソルを元の位置に戻す #####
SendMessage(hEdit, EM_SETSEL, pUndo->nStart, pUndo->nStart) Case UNDO_PASTE
LockWindowUpdate(hEdit)
'貼り付けられた範囲を選択する
chrg.cpMin=pUndo->nStart
chrg.cpMax=pUndo->nStart+pUndo->nLength
SendMessage(hEdit, EM_EXSETSEL, 0, VarPtr(chrg))
'選択した範囲を上書きされた文字列で上書きする
SendMessage(hEdit, EM_REPLACESEL, 0, pUndo->szText)
'カーソルを元の位置に戻す
SendMessage(hEdit,EM_SETSEL,pUndo->nStart,pUndo->nStart)
LockWindowUpdate(NULL)
Case UNDO_CUT
'nStartで指定された位置に文字を挿入
chrg.cpMin=pUndo->nStart
SendMessage(hEdit, EM_REPLACESEL, 0, pUndo->szText)
Case UNDO_COLORCUT
'nStartで指定された位置に文字を挿入
chrg.cpMin=pUndo->nStart
SendMessage(hEdit, EM_REPLACESEL, 0, pUndo->szText)
Case UNDO_KANJIINPUT
'##### アンドゥ後のテキストの長さ #####
Length=Length-pUndo->nLength+Len(pUndo->szText)
'##### アンドゥ後のバッファ確保 #####
'MoveMemory使うからcallocで確保する
pNewText=calloc(Length+1)
'##### 先頭からカーソルまでをコピー #####
MoveMemory(pNewText, pNowText, pUndo->nStart)
'##### 入力時に消された文字を追加する #####
'文字選択状態で文字入力した時の為
lstrcat(pNewText, StrPtr(pUndo->szText))
'##### カーソルから最後までをコピー #####
lstrcat(pNewText, pNowText+pUndo->nStart+pUndo->nLength+1)
'##### 新しいバッファを設定 #####
SetWindowText(hEdit, pNewText)
'##### カーソルを元の位置に戻す #####
SendMessage(hEdit, EM_SETSEL, pUndo->nStart, pUndo->nStart)
End Select
'##### 一番新しいアンドゥバッファを削除する 始まり #####
ptmp=pUndo->pNext
free(pUndo)'リドゥにも対応する場合はfreeせずにリドゥバッファに渡す(リドゥバッファを新たに作成する必要あり)
pUndo=ptmp
'##### 一番新しいアンドゥバッファを削除する 終わり #####
'##### 後始末 #####
SendMessage(hEdit, EM_EXGETSEL, 0, VarPtr(chrg))
MainWnd_IDM_REDRAW_MenuClick()
If pNowText Then free(pNowText)
If pNewText Then free(pNewText)
End Sub
'クリップボードからテキストデータを貼り付ける
Sub CallPaste()
Dim chrg As CHARRANGE
Dim pszPasteText As BytePtr
Dim lpszPasteText As BytePtr
Dim dwlength As DWord
Dim lpszbuf As BytePtr, lpszbuf2 As BytePtr
Dim dwEvent As DWord
If SendMessage(hEdit, EM_CANPASTE, 0, 0) Then
'クリップボードをオープンする
If OpenClipboard(NULL)=FALSE Then
MessageBox(hMainWnd, "クリップボードのオープンに失敗", "Error", MB_OK or MB_ICONSTOP)
Exit Sub
End If
'クリップボードの内容を読み取る
pszPasteText=GetClipboardData(CF_TEXT)
If pszPasteText=NULL Then Exit Sub
'クリップボードの内容を他の変数にコピー
lpszPasteText=malloc(lstrlen(pszPasteText)+1)
lstrcpy(lpszPasteText, pszPasteText)
'クリップボードを閉じる
CloseClipboard()
'---ここからアンドゥ関係処理---
'カーソルの位置を取得し、サイズを計算してバッファを確保
SendMessage(hEdit, EM_EXGETSEL, 0, VarPtr(chrg))
dwlength=chrg.cpMax-chrg.cpMin
lpszbuf=malloc(GetWindowTextLength(hEdit)+1)
lpszbuf2=calloc(dwlength+1)
'現在のテキストを取得
GetWindowText(hEdit, lpszbuf, GetWindowTextLength(hEdit)+1)
'選択文字を取得
MoveMemory(lpszbuf2, lpszbuf+chrg.cpMin, dwlength)
'アンドゥに追加
AddUndo(UNDO_PASTE, chrg.cpMin, lpszbuf2, lstrlen(lpszPasteText)+1)
'---ここまで---
'クリップボードの内容をhEditに挿入
SendMessage(hEdit, EM_REPLACESEL, 0, lpszPasteText)
'イベントマスクからENM_CHANGEをはずす
dwEvent=SendMessage(hEdit, EM_GETEVENTMASK, 0, 0)
SendMessage(hEdit, EM_SETEVENTMASK, 0, dwEvent xor ENM_CHANGE)
'文字色を変更する
SetKeywordColor(0, -1)
'イベントマスクにENM_CHANGEを追加する
dwEvent=SendMessage(hEdit, EM_GETEVENTMASK, 0, 0)
SendMessage(hEdit, EM_SETEVENTMASK, 0, dwEvent or ENM_CHANGE)
'後処理
free(lpszPasteText)
free(lpszbuf)
free(lpszbuf2)
End If
End Sub
Sub CallCut()
Dim chrg As CHARRANGE
Dim pszCutText As BytePtr
Dim hGlobalMem As DWord
Dim dwCutTextLength As DWord
Dim length As DWord
Dim buf As BytePtr
Dim buf2 As BytePtr
SendMessage(hEdit, EM_EXGETSEL, 0, VarPtr(chrg))
If chrg.cpMin<>chrg.cpMax Then
'クリップボードをオープンする
If OpenClipboard(NULL)=FALSE Then
MessageBox(hMainWnd, "クリップボードのオープンに失敗", "Error", MB_OK or MB_ICONSTOP)
Exit Sub
End If
'クリップボードを空にする
EmptyClipboard()
'クリップボードに選択された文字列をコピーする
dwCutTextLength=GetWindowTextLength(hEdit)
hGlobalMem=GlobalAlloc(GHND or GMEM_SHARE, dwCutTextLength+1)
pszCutText=GlobalLock(hGlobalMem)
If pszCutText=NULL Then
MessageBox(hMainWnd, "クリックボードにコピーするテキスト用のバッファ確保取得に失敗", "Error ", MB_OK or MB_ICONSTOP)
Exit Sub
End If
SendMessage(hEdit, EM_GETSELTEXT, 0, pszCutText)
GlobalUnlock(hGlobalMem)
SetClipboardData(CF_TEXT, hGlobalMem)
CloseClipboard()
'---ここからアンドゥ関係処理---
'バッファを確保
length=chrg.cpMax-chrg.cpMin
buf=malloc(GetWindowTextLength(hEdit)+1)
buf2=calloc(length+1)
'現在のテキストを取得
GetWindowText(hEdit, buf, GetWindowTextLength(hEdit)+1)
'切り取られる部分の文字を取得
SendMessage(hEdit, EM_GETSELTEXT, 0, buf2)
'アンドゥ追加
AddUndo(UNDO_CUT, chrg.cpMin, buf2, Len(buf2))
'---ここまで---
'選択された範囲を無文字に置換する
SendMessage(hEdit, EM_REPLACESEL, 0, "")
'後処理
free(buf)
free(buf2)
End If
End Sub
Sub CallColorCut()
Dim chrg As CHARRANGE
Dim pszCutText As BytePtr
Dim hGlobalMem As DWord
Dim dwCutTextLength As DWord
Dim length As DWord
Dim buf As BytePtr
Dim buf2 As BytePtr
SendMessage(hEdit, EM_EXGETSEL, 0, VarPtr(chrg))
If chrg.cpMin<>chrg.cpMax Then
'---ここからアンドゥ関係処理---
'バッファを確保
length=chrg.cpMax-chrg.cpMin
buf=malloc(GetWindowTextLength(hEdit)+1)
buf2=calloc(length+1)
'現在のテキストを取得
GetWindowText(hEdit, buf, GetWindowTextLength(hEdit)+1)
'切り取られる部分文字を取得
SendMessage(hEdit, EM_GETSELTEXT, 0, buf2)
'アンドゥ追加
AddUndo(UNDO_COLORCUT, chrg.cpMin, buf2, Len(buf2))
'---ここまで---
SendMessage(hEdit, WM_CUT, 0, 0)
'後処理
free(buf)
free(buf2)
End If
End Sub
Sub CallAllSelect()
Dim chrg As CHARRANGE
chrg.cpMax=-1
SendMessage(hEdit, EM_EXSETSEL, 0, VarPtr(chrg))
End Sub
Function EditProc(hWnd As HWND,message As DWord,wParam As WPARAM,lParam As LPARAM) As LRESULT
Dim nStart As Long, nEnd As Long, length As Long
Dim buf As BytePtr, buf2 As BytePtr, buf3 As BytePtr
Dim chrg As CHARRANGE
If Not (GetAsyncKeyState(VK_CONTROL) and &H8000) Then
Select Case message
Case WM_IME_STARTCOMPOSITION
'カーソル位置を取得
SendMessage(hEdit, EM_EXGETSEL, 0, VarPtr(chrg))
IMEStartCharIndex.cpMin=chrg.cpMin
IMEStartCharIndex.cpMax=chrg.cpMax
Case WM_IME_ENDCOMPOSITION
'カーソル位置を取得
SendMessage(hEdit, EM_EXGETSEL, 0, VarPtr(chrg))
If IMEStartCharIndex.cpMin<>chrg.cpMin Then
If IMEStartCharIndex.cpMin<>IMEStartCharIndex.cpMax Then
length=chrg.cpMax-IMEStartCharIndex.cpMin
buf2=malloc(GetWindowTextLength(hEdit)+1)
SendMessage(hEdit, EM_GETSELTEXT, 0, buf2)
AddUndo(UNDO_KANJIINPUT, IMEStartCharIndex.cpMin, buf2, length)
Else
length=chrg.cpMax-IMEStartCharIndex.cpMin
buf2=malloc(length+1)
lstrcpy(buf2, "")
AddUndo(UNDO_KANJIINPUT, IMEStartCharIndex.cpMin, buf2, length)
End If
End If
Case WM_UNDO
'EDITの本来のアンドゥ処理をさせない
Exit Function
Case WM_PASTE
Exit Function
Case WM_KEYDOWN
If wParam=Asc("Z") and (GetAsyncKeyState(VK_CONTROL) and &H8000) Then
'Control+Zが押された
'自前のアンドゥを行う
CallUndo()
Exit Function
ElseIf wParam=Asc("V") and (GetAsyncKeyState(VK_CONTROL) and &H8000) Then
CallPaste()
Exit Function
ElseIf wParam=Asc("A") and (GetAsyncKeyState(VK_CONTROL) and &H8000) Then
CallAllSelect()
Exit Function
ElseIf wParam>=Asc("A") and wParam<=Asc("Z") or wParam>=Asc("0") and wParam<=Asc("9") or _
(wParam>=VK_NUMPAD0 and wParam<=VK_DIVIDE xor wParam=VK_SEPARATOR) Then
'入力が数字の0~9、アルファベットのA~Zの場合
'IME ONや、上書きモードは考慮されていません
'カーソル位置を取得
SendMessage(hEdit, EM_EXGETSEL, 0, VarPtr(chrg))
'##### 選択バイト数 #####
length=chrg.cpMax-chrg.cpMin
'##### 現在のテキストバッファを確保 #####
buf=malloc(GetWindowTextLength(hEdit)+1)
'##### 選択文字のバッファを確保 #####
buf2=calloc(length+1)
'##### 現在のテキスト取得 #####
GetWindowText(hEdit, buf, GetWindowTextLength(hEdit)+1)
'##### 選択文字取得 #####
MoveMemory(buf2, buf+chrg.cpMin, length)
'##### アンドゥ追加 #####
AddUndo(UNDO_INPUT, chrg.cpMin, buf2, 1)
ElseIf wParam=VK_BACK Then
'ユーザーがBackSpaceキーを押したとき
'カーソル位置を取得
SendMessage(hEdit, EM_EXGETSEL, 0, VarPtr(chrg))
'バッファを確保
length=chrg.cpMax-chrg.cpMin
buf=malloc(GetWindowTextLength(hEdit)+1)
buf2=calloc(length+1)
If chrg.cpMax=0 Then goto *EditProcEnd
If chrg.cpMin<>chrg.cpMax Then
'除去される部分文字を取得
SendMessage(hEdit, EM_GETSELTEXT, 0, buf2)
'アンドゥ追加
AddUndo(UNDO_BACK, chrg.cpMax, buf2, Len(buf2))
Else
length=1
buf2=calloc(length+1)
buf3=calloc(3)
'現在のテキストを取得
GetWindowText(hEdit, buf, GetWindowTextLength(hEdit)+1)
'除去される文字を取得
MoveMemory(buf2, buf+chrg.cpMin-1, length)
MoveMemory(buf3, buf+chrg.cpMin-1, 2)
If IsDBCSLeadByte(buf3[0]) Then
'日本語用アンドゥ追加
AddUndo(UNDO_BACK, chrg.cpMin, buf3, 2)
free(buf3)
Else
'アンドゥ追加
AddUndo(UNDO_BACK, chrg.cpMin, buf2, length)
End If
End If
ElseIf wParam=VK_DELETE Then
'ユーザーがDeleteキーを押したとき
'カーソル位置を取得
SendMessage(hEdit, EM_EXGETSEL, 0, VarPtr(chrg))
'バッファを確保
length=chrg.cpMax-chrg.cpMin
buf=malloc(GetWindowTextLength(hEdit)+1)
buf2=calloc(length+1)
If chrg.cpMin<>chrg.cpMax Then
'除去される部分文字を取得
SendMessage(hEdit, EM_GETSELTEXT, 0, buf2)
'アンドゥ追加
AddUndo(UNDO_DELETE, chrg.cpMax, buf2, Len(buf2))
Else
If GetWindowTextLength(hEdit)=chrg.cpMin Then goto *EditProcEnd
length=1
buf2=calloc(length+1)
buf3=calloc(3)
'現在のテキストを取得
GetWindowText(hEdit, buf, GetWindowTextLength(hEdit)+1)
'除去される文字を取得
MoveMemory(buf2, buf+chrg.cpMin, length)
MoveMemory(buf3, buf+chrg.cpMin, 2)
Debug
If IsDBCSLeadByte(buf3[0]) Then
'日本語用アンドゥ追加
AddUndo(UNDO_BACK, chrg.cpMin, buf3, 2)
free(buf3)
Else
'アンドゥ追加
AddUndo(UNDO_BACK, chrg.cpMin, buf2, length)
End If
End If
End If
End Select
End If
*EditProcEnd
EditProc=CallWindowProc(pOldEditProc,hWnd,message,wParam,lParam)
free(buf)
free(buf2)
End Function[/code][/hide]
大変...。