PDA

View Full Version : گفتگو: برقراري ارتباط با كيبورد!



رافعی مهدی
شنبه 02 آذر 1387, 10:39 صبح
موضوعي كه در اين پست مطرح شده پاسخي است به اين مشكل كه چگونه مي توان با كيبورد ارتباط مناسبي برقرار كرد؟ راستش اين موضوع وقت زيادي از من گرفت، اين بود كه تصميم گرفتم نتايج رو يكجا در اختيار دوستان قرار بدهم.
__________________________________________________ __________________


برقراري ارتباط با كيبورد شامل دو مبحث زير مي‌شود:
1- دريافت صحيح كليد فشرده شده (يا تركيبي از چند كليد)
2- ارسال فرماني در جهت شبيه سازي فشردن هر كليد دلخواه (يا تركيبي از كليدها)


1- چگونه بفهميم كه چه كليدي از كيبورد فشرده شده است؟
طبيعتاً پيش از هر كار ديگري به سراغ رويداد KeyDown ميرويم. بياييد اين رويداد را مشخصاً در مورد كليدهاي شيفت بررسي كنيم. چراكه در مورد كليدهاي مربوط به اعداد يا حروف مشكل خاصي وجود ندارد.



private void SomeControl_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Shift) // 1
{
// Some codes
}
if (e.KeyCode == Keys.ShiftKey) // 2
{
// Some codes
}
if (e.KeyCode == Keys.LShiftKey) // 3
{
// Some codes
}
if (e.KeyCode == Keys.RShiftKey) // 4
{
// Some codes
}

}

اكنون با اجراي كد فوق دكمه هاي شيفت چپ و راست را بطور جداگانه فشار مي دهيم. از ميان عبارات شرطي نوشته شده در كد فوق تنها شرط دوم درست و ما بقي نادرستند، در حالي كه انتظار مي رفت عبارات شرطي 3 و 4 به ترتيب با فشرده شدن كليدهاي شيفت چپ و راست درست باشند.


براي حل اين مشكل پاسخهايي در سايت هاي مختلف ارائه شده است. راه حل‌هاي ارائه شده به دو دسته‌ي اصلي تقسيم بندي مي‌شوند:
الف- در دست گرفتن كنترل صفحه كليد (Keyboard Hooking)
ب- استفاده از توابع API

رافعی مهدی
شنبه 02 آذر 1387, 10:40 صبح
الف– هوك كردن كيبورد (1)
كد ارائه شده در پيوست، تحت عنوان KeyboardManager را در نظر بگيريد. براي استفاده از اين كد لازم است كلاس KeyboardManager را به پروژه ي خود اضافه كنيد، سپس در هر كلاسي كه مي خواهيد در آن كنترل صفحه كليد را در دست بگيريد، خطوط زير را بنويسيد:




private KeyboardManager keyboardManager = new KeyboardManager();
:
:
keyboardManager.HookedKeys.Add(Keys.LShiftKey);
keyboardManager.HookedKeys.Add(Keys.RShiftKey);
keyboardManager.KeyDown += new KeyEventHandler(keyboardManager_KeyDown);
keyboardManager.KeyUp += new KeyEventHandler(keyboardManager_KeyUp);
:
:
void keyboardManager_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.LShiftKey)
{

}
else if (e.KeyCode == Keys.RShiftKey)
{

}
}

void keyboardManager_KeyUp(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.LShiftKey)
{

}
else if (e.KeyCode == Keys.RShiftKey)
{

}
}


ملاحظه مي شود كه اين بار فشرده شدن كليدهاي شيفت چپ و راست از يكديگر تشخيص داده مي‌شوند!

__________________________________________________ ___________________
(1): براي هوك كردن كيبورد، هيچ يك از كدهاي ارائه شده‌اي را كه من امتحان كردم بي نقص نبودند، بنابراين كد جديدي نوشتم كه در واقع تركيبي از همان كدهاي متعدد ارائه شده در سايت‌هاي مختلف است ولي مشكلات آنها را ندارد. (اصل كد مربوط به سايت Code Project است.)

رافعی مهدی
شنبه 02 آذر 1387, 10:41 صبح
ب- استفاده از توابع API
اين روش برگرفته از كد يكي از كارمندان شركت مايكروسافت به نام Guo Surfer است:



public class MyClass
{
private const int WM_KEYDOWN = 0x100;
protected override void WndProc(ref Message m)
{
if (m.Msg == WM_KEYDOWN)
{
if (m.WParam == (IntPtr)(Keys.LShiftKey))
{

}
elseif (m.WParam == (IntPtr)(Keys.RShiftKey))
{

}
}
base.WndProc(ref m);
}
}

به نظر مي‌رسد كه استفاده از اين روش ساده تر از روش اول باشد.

رافعی مهدی
شنبه 02 آذر 1387, 11:51 صبح
2- چگونه فشرده شدن كليد خاصي از صفحه كليد را شبيه سازي كنيم؟
براي انجام دادن اين كار ابتدا سراغ متد Send از كلاس SendKeys مي رويم...




SendKeys.Send("+");


كد فوق به اين معني است كه فشرده شدن كليد شيفت بايد شبيه سازي شود اما اينكه كليد شيفت چپ يا راست، معلوم نيست!
براي حل اين مشكل مي‌توان از كد زير استفاده كرد:



using System.Runtime.InteropServices;
using System.Diagnostics;

private const int WM_KEYDOWN = 0x100;
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = false)]
static extern IntPtr SendMessage(IntPtr hWnd, int Msg, int wParam, int lParam);

private void button1_Click(object sender, EventArgs e)
{
Keys key = Keys.RShiftKey;//Right shift key
SendMessage(Process.GetCurrentProcess().MainWindow Handle, WM_KEYDOWN, (int)key, 1);
}

protected override void DefWndProc(refMessage m)
{
if (m.Msg == WM_KEYDOWN)
MessageBox.Show(m.WParam.ToString());
base.DefWndProc(ref m);
}


در كد فوق بجاي استفاده از Process.GetCurrentProcess().MainWindowHandle مي‌توان از MyControl.Handle استفاده كرد.