ホテル管理システム
ogi
yesterday 1a1c8e71fcd14858f595029f089b2d4a00202b32
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
using System;
using System.Collections.Generic;
using System.Text;
using System.ComponentModel;
using System.Drawing;
using System.Windows.Forms;
using System.Runtime.InteropServices;
 
namespace HotelPms.Share.Windows.Component
{
    /// <summary>
    /// 拡張機能を持ったTextBoxです。
    /// IMEを利用して入力したコンテキストを従属するコントロールまたはイベントイベントデータとして渡す機能を持ったTextBox。
    /// 使用例:全角入力された文字を半角カナ文字に変換して渡す。
    /// </summary>
    [ToolboxBitmap(typeof(System.Windows.Forms.TextBox))]
    public class TextBoxFurigana : CTextBox
    {
        /// <summary>
        /// ImeComposed イベントを処理するメソッドを表します。
        /// </summary>
        /// <param name="sender">イベントのソース。</param>
        /// <param name="e">変換文字列情報。</param>
        public delegate void ImeComposedEventHandler(object sender, ImeComposedEventArgs e);
 
        /// <summary>
        /// IME入力文字が確定されたとき発生するイベントを定義します。
        /// </summary>
        [Description("IME入力文字が確定されたとき発生するイベントです。"), Category("キー")]
        public event ImeComposedEventHandler ImeComposed = null;
 
        private const int WM_CHAR = 0x0102;
        private const int WM_IME_COMPOSITION = 0x010F;
        private const int GCS_RESULTREADSTR = 0x0200;
 
        private System.Windows.Forms.Control m_Control = null;      // 連結する子コントロール
 
        /// <summary>
        /// TextBoxEx クラスの新しいインスタンスを初期化します。
        /// </summary>
        public TextBoxFurigana()
        {
        }
 
        /// <summary>指定されたウィンドウに関連付けられている入力コンテキストを取得します。</summary>
        [DllImport("Imm32.dll")]
        public static extern int ImmGetContext(IntPtr hWnd);
 
        /// <summary>変換文字列に関する情報を取得します。</summary>
        [DllImport("Imm32.dll")]
        public static extern int ImmGetCompositionString(int hIMC, int dwIndex, StringBuilder lpBuf, int dwBufLen);
 
        /// <summary>
        /// 入力コンテキストを解放し、コンテキスト内の関連メモリのロックを解除します。
        /// アプリケーションで ImmGetContext 関数を呼び出したら、必ず対応する ImmReleaseContext 関数を呼び出さなければなりません。
        /// </summary>
        [DllImport("Imm32.dll")]
        public static extern bool ImmReleaseContext(IntPtr hWnd, int hIMC);
 
        // IMEの状態取得
        [DllImport("Imm32.dll")]
        private static extern int ImmGetOpenStatus(int hIMC);
 
        /// <summary>
        /// 従属するコントロールを取得または設定します。 
        /// </summary>
        [Description("連結する子コントロールを取得または設定します。"), Category("動作"), DefaultValue(null)]
        public Control ChildControl
        {
            get { return m_Control; }
            set { m_Control = value; }
        }
 
 
 
        /// <summary>
        /// キーが押された時呼ばれます。 
        /// </summary>
        /// <param name="m">処理対象の System.Windows.Forms.Message。</param>
        protected override void WndProc(ref Message m)
        {
            if ((ImeComposed != null || ChildControl != null))
            {
                if (m.Msg == WM_IME_COMPOSITION)
                {
                    // 変換が確定状態か確認する
                    if (((int)m.LParam & GCS_RESULTREADSTR) > 0)
                    {
                        // 入力コンテキストを取得します
                        int hIMC = ImmGetContext(this.Handle);
 
                        //int status = ImmGetOpenStatus(hIMC);
                        
                        // 変換文字列に関する情報を取得するのに必要なバッファサイズを取得します。
                        int strLen = ImmGetCompositionString(hIMC, GCS_RESULTREADSTR, null, 0);
 
                        // 文字列バッファを確保します。
                        StringBuilder str = new StringBuilder(strLen);
 
                        // 変換文字列に関する情報を取得します。
                        ImmGetCompositionString(hIMC, GCS_RESULTREADSTR, str, str.Capacity);
 
                        // 入力コンテキストを解放します。
                        ImmReleaseContext(this.Handle, hIMC);
 
                        //System.Diagnostics.Debug.WriteLine(string.Format("Status:{0},String:{1}",status, str.ToString(0, strLen)));
 
                        //イベントデータの設定&起動
                        if (ImeComposed != null)
                        {
                            //文字列を対象長さ分切り出して(後ろのゴミを排除して)イベントデータを生成する
                            if (str.Length >= strLen)
                            {
                                ImeComposed(this, new ImeComposedEventArgs(str.ToString(0, strLen), GetSelectionMode()));
                            }
                        }
 
                        //従属コントロールに入力文字文字列を設定する
                        if (ChildControl != null)
                        {
                            if (str.Length >= strLen)
                            {
                                SetCompositionStr(ChildControl, str.ToString(0, strLen));
                            }
                            else
                            {
                                //MessageBox.Show("エラー::取得する長さが異常です。" + "Text=" + str.ToString() + "/長さ=" + str.Length + "/取得長さ=" + strLen);
                                //SetCompositionStr(ChildControl, str.ToString(0, str.Length));
                            }
                        }
                    }
                    else if ((int)m.LParam == 6144)
                    {
                        try
                        {
                            //従属コントロールに入力文字文字列を設定する
                            if (ChildControl != null)
                            {
                                //従属コントロールに入力文字文字列を設定
                                if (InputLanguage.CurrentInputLanguage.LayoutName.Contains("ATOK")) { SetCompositionStr(ChildControl, " "); }
                            }
                        }
                        catch { }
                    }
                }
                else if (m.Msg == WM_CHAR)
                {
                    //半角英数字 //20121002 毛利 Redmine#2795 #2796
                    int hIMC = ImmGetContext(this.Handle);
                    if (ImmGetOpenStatus(hIMC) == 0)
                    {
                        char chr = Convert.ToChar(m.WParam.ToInt32() & 0xff);
 
                        if (m.WParam.ToInt32() >= 32)
                        {
                            //イベント起動
                            string str = chr.ToString();
                            //System.Diagnostics.Debug.WriteLine(string.Format("String:{0}", str));
 
                            //イベントデータの設定&起動
                            if (ImeComposed != null)
                            {
                                ImeComposed(this, new ImeComposedEventArgs(str, GetSelectionMode()));
                            }
 
                            //従属コントロールに入力文字文字列を設定する
                            if (ChildControl != null)
                            {
                                try
                                {
                                    //従属コントロールに入力文字文字列を設定
                                    SetCompositionStr(ChildControl, str);
                                }
                                catch { }
                            }
                        }
                    }
                    ImmReleaseContext(this.Handle, hIMC);
                }
            }
 
            //if (!this.IsDisposed)
            //{
            //    if (this.Parent != null)
            //    {
            //        if (!base.IsDisposed)
            //        {
            //            try
            //            {
                            base.WndProc(ref m);
            //            }
            //            catch
            //            {
            //                //伝票入力で存在するコードを入力した後、科目名のテキストボックスをクリックすると
            //                //なんかここで落ちてた。回避の方法がよくわからないので、とりあえずtry-catchで。
            //            }
            //        }
            //    }
            //}
        }
 
        /// <summary>
        /// 従属するコントロールに入力文字を設定するメッソド 
        /// </summary>
        /// <param name="cntl">入力した文字列を設定するコントロール。</param>
        /// <param name="inputStr">IMEを利用して入力した文字列。</param>
        protected virtual void SetCompositionStr(System.Windows.Forms.Control cntl, string inputStr)
        {
            // 入力開始位置が先頭か確認する
 
            inputStr.Replace("'", string.Empty);
            if (this.SelectionStart == 0)
            {
                // 選択範囲が既入力文字列全体と一致するか確認する
 
                if (this.SelectionLength == this.Text.Length)
                {
                    // 既入力文字列を選択して入力する場合、入力文字列で置換える
                    cntl.Text = inputStr;
                }
                else
                {
                    // 既入力文字列の先頭に入力文字列を挿入する
                    cntl.Text = inputStr + cntl.Text;
                }
            }
            else
            {
                // 先頭以外の場合、全て追加設定する
                cntl.Text += inputStr;
            }
 
            //20100108 ogi DBの制限を超えないように対応
            if (cntl.Text.Length > (cntl as TextBox).MaxLength) { cntl.Text = cntl.Text.Substring(0, (cntl as TextBox).MaxLength); }
        }
 
        private int GetSelectionMode()
        {
            if (this.SelectionStart == 0)
            {
                // 選択範囲が既入力文字列全体と一致するか確認する
                if (this.SelectionLength == this.Text.Length)
                {
                    return 0;
                }
                else
                {
                    // 既入力文字列の先頭に入力文字列を挿入する
                    return 1;
                }
            }
            else
            {
                // 先頭以外の場合、全て追加設定する
                return 2;
            }
 
        }
 
        /// <summary>
        /// COMMENT:202061012 毛利 機能追加
        /// メインテキストが空白になった場合、子テキストも空白に。
        /// </summary>
        /// <param name="e"></param>
        protected override void OnTextChanged(EventArgs e)
        {
            if (this.Text == "")
            {
                if (ChildControl != null) { this.ChildControl.Text = ""; }
                if (ImeComposed != null) { ImeComposed(this, new ImeComposedEventArgs(string.Empty, 3)); }
            }
 
            base.OnTextChanged(e);
        }
 
        /// <summary>
        /// 変換文字列情報イベントデータ。
        /// </summary>
        [Serializable]
        public class ImeComposedEventArgs : System.EventArgs
        {
            /// <summary>変換文字列。</summary>
            private string m_InputStr;
            private int m_SelectionMode;   //0:置換える、1:先頭に挿入、2:追加
 
            /// <summary>
            /// 変換文字列情報イベントデータクラスの新しいインスタンスを初期化します。
            /// </summary>
            public ImeComposedEventArgs()
            {
                m_InputStr = "";
            }
            /// <summary>
            /// 変換文字列情報イベントデータクラスの新しいインスタンスを初期化します。
            /// </summary>
            /// <param name="inputStr">IMEを利用して入力した文字列。</param>
            public ImeComposedEventArgs(string inputStr, int selectionMode)
            {
                m_InputStr = inputStr;
                m_SelectionMode = selectionMode;
            }
 
            /// <summary>
            /// IMEを利用して入力した文字列を取得します。
            /// </summary>
            public string InputString
            {
                get { return m_InputStr; }
            }
 
            /// <summary>
            /// 0:置換える、1:先頭に挿入、2:追加
            /// </summary>
            public int SelectionMode
            {
                get { return m_SelectionMode; }
            }
        }
    }
}