PosKeyboard 服務物件會讀取 POS 鍵盤上的按鍵。 POS 鍵盤可以是輔助鍵盤,也可能是包含系統鍵盤部分或全部按鍵的虛擬鍵盤。 在 Microsoft Point of Service for .NET(POS for .NET)中,POS 鍵盤 的基底 類別為 PosKeyboardBase。
PosKeyboard 服務物件遵循一般輸入裝置模型:
- 當從 POS 鍵盤接收到輸入時,會排隊一個 DataEvent。
- 如果 AutoDisable 屬性為 true,當 DataEvent 事件被排隊時,裝置會自動停用。 這是由 PosKeyboardBase 類別自動執行的。
- 當 DataEventEnabled 屬性為真且其他事件傳遞需求符合時,將送達一個佇列中的 DataEvent 事件給應用程式。 PosKeyboardBase 類別會自動管理事件傳遞。
- 若在收集或處理輸入時發生錯誤,則將 ErrorEvent 事件排隊,當 DataEventEnabled 設為 true 且符合其他事件傳遞需求時,該事件會送達給應用程式。
- 由 PosKeyboardBase 類別維護的 DataCount 屬性可讀取以取得排隊事件數量。
- 所有排隊輸入皆可透過呼叫 ClearInput() 刪除。
POS 鍵盤是專用裝置:
- 應用程式必須先取得該裝置的權利,才能啟用。
- 應用程式必須在裝置開始讀取輸入前先宣稱並啟用該裝置。
本節包含一個範例 PosKeyboard 服務物件,能產生模擬按鍵,並透過 DataEvents 傳送給應用程式。 此範例依賴於 《介紹服務物件讀取線程》中所呈現的線程輔助物件。 要編譯這個範例,你需要包含該主題的程式碼。
撰寫服務物件
新增對 Microsoft.PointofService、Microsoft.PointOfService.BaseServiceObjects 及 System.Threading 的使用指令。
新增全域屬性 PosAssembly。
為您的專案選擇合適的命名空間名稱。
建立一個由 PosKeyboardBase 衍生的服務物件類別。
將
ServiceObject屬性新增至您的服務物件類別中,並使用 DeviceType.PosKeyboard 作為裝置類型。
若要為服務物件的範例鍵盤新增功能
建立一個執行緒輔助類別 KeyboardThreadingObject,源自服務物件讀取執行緒區段的 ServiceObjectThreadHelper。
在 KeyboardThreadingObject 類別中實作 ServiceObjectThreadProcedure 方法。 這是會在另一個執行緒上執行的程序。 在下方範例程式碼中,此方法模擬鍵盤輸入。
此範例類別實作了一個名為 SendKey 的方法,以及另一個名為 ChangePowerState 的方法。 這些方法是包裝在受保護成員外部的。 由於這些資料受到保護,無法直接從執行緒物件呼叫。
覆寫 PosCommon.Open 方法,指定此服務物件所支援的功能,並建立新的執行緒輔助物件。
專門覆寫 PosCommon.DeviceEnable 以便特定用於開啟 和 關閉 執行緒輔助器。
實作 PosCommon 的抽象虛擬方法,提供最小功能。
執行應用程式
此範例服務物件可與隨 POS for .NET 軟體開發套件(SDK)提供的測試應用程式同時執行。
測試服務物件
啟動測試應用程式,並從鍵盤下拉選單中選擇 SamplePosKeyboard。
開啟並認領該裝置,然後勾選DeviceEnabled以啟用該裝置。
勾選 DataEventEnabled 方框後,服務物件可將單一模擬金鑰傳送給應用程式。 PosKeyboardBase 類別在呼叫 KeyDown 時會自動地將 DataEvent 加入佇列。
選擇「 自動啟用資料事件 」框後,服務物件能以兩秒間隔繼續傳送字元。
服務物件會為字元「a」到「z」發送模擬按鍵。 之後會傳送一個 StatusUpdateEvent 事件,表示該裝置已離線。 當 Properties.PowerState 變更時,PosKeyboardBase 類別會自動傳送此事件。
Example
本範例示範如何開發一個簡單的 PosKeyboard 服務物件。 它支援獨立的讀取執行緒,以非同步地將 DataEvents 傳送給應用程式。 編譯完成後,你可以將服務物件與 POS for .NET SDK 附帶的測試應用程式一同執行。
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using Microsoft.PointOfService;
using Microsoft.PointOfService.BaseServiceObjects;
[assembly: PosAssembly("Service Object Contractors, Inc.")]
namespace SOSamples.Keyboard
{
[ServiceObject(
DeviceType.PosKeyboard,
"SamplePosKeyboard",
"Sample PosKeyboard Service Object",
1,
9)]
public class SampleKeyboard : PosKeyboardBase
{
KeyboardThreadingObject ReadThread = null;
public SampleKeyboard()
{
// DevicePath must be set before Open() is called.
// In the case of Play and Plug hardware, the
// POS for .NET Base class will set this value.
DevicePath = "Sample Keyboard";
// NOTE: You can test the power notification events
// sent from this Service Object by selecting the
// "Power Notify" check box.
// Let the application know advanced power
// reporting is supported.
Properties.CapPowerReporting = PowerReporting.Advanced;
Properties.CapKeyUp = false;
}
~SampleKeyboard()
{
// Code added from previous sections to terminate
// the read thread started by the thread-helper
// object.
if (ReadThread != null)
{
ReadThread.CloseThread();
}
Dispose(false);
}
// Expose the protected KeyDown() method so that it can be
// called from our threading helper.
public void SendKey(int key)
{
KeyDown(key);
}
// Expose the protected PowerState property so it can be
// changed from the threading helper.
public void ChangePowerState(PowerState state)
{
Properties.PowerState = state;
}
#region Override Virtual PosCommon Members
public override void Open()
{
base.Open();
// Create the reader-thread object.
ReadThread = new KeyboardThreadingObject(this);
}
public override bool DeviceEnabled
{
get
{
return base.DeviceEnabled;
}
set
{
if (value != base.DeviceEnabled)
{
base.DeviceEnabled = value;
if (value == false)
{
// Stop the reader thread when the device
// is disabled.
ReadThread.CloseThread();
}
else
{
try
{
// By enabling the device, start the
// reader thread.
ReadThread.OpenThread();
}
catch (Exception e)
{
base.DeviceEnabled = false;
if (e is PosControlException)
throw;
throw new PosControlException(
"Unable to Enable Device",
ErrorCode.Failure, e);
}
}
}
}
}
#endregion Override Virtual PosCommon Members
#region Implement Abstract PosCommon Members
private string MyHealthText = "";
// PosCommon.CheckHealthText.
public override string CheckHealthText
{
get
{
// VerifyState(mustBeClaimed,
// mustBeEnabled).
VerifyState(false, false);
return MyHealthText;
}
}
// PosCommon.CheckHealth.
public override string CheckHealth(
HealthCheckLevel level)
{
// Verify that device is open, claimed and enabled.
VerifyState(true, true);
// Your code here:
// Check the health of the device and return a
// descriptive string.
// Cache result in the CheckHealthText property.
MyHealthText = "Ok";
return MyHealthText;
}
// PosCommon.DirectIOData.
public override DirectIOData DirectIO(
int command,
int data,
object obj)
{
// Verify that the device is open.
VerifyState(false, false);
return new DirectIOData(data, obj);
}
#endregion Implement Abstract PosCommon Members
}
#region Thread Helper Class
public class KeyboardThreadingObject :
ServiceObjectThreadHelper, IDisposable
{
// This is a helper class which will depend on
// being able to call back into the actual Service
// Object to pass along data. However, you cannot
// keep a strong reference to the Service Object,
// since that may prevent clean disposal, leaving
// hardware resources unavailable to other processes.
// Therefore, you create a weak reference. From this
// reference, you can get a temporary strong reference,
// which you can act on and then release.
WeakReference ServiceObjectReference;
// The name of the Service Object.
string ObjectName;
public KeyboardThreadingObject(SampleKeyboard so)
{
ObjectName = GetType().Name;
ServiceObjectReference = new WeakReference(so);
}
// This method will be called during initialization.
public override void ServiceObjectThreadOpen()
{
Logger.Info(ObjectName, "Keyboard Thread Open");
}
// This method will be called curing shutdown.
public override void ServiceObjectThreadClose()
{
Logger.Info(ObjectName, "Keyboard Thread Open");
}
// Your code used to monitor your device for input should
// go here. The implementation below generates simulated
// input as an example.
public override void ServiceObjectThreadProcedure(
AutoResetEvent ThreadStopEvent)
{
Logger.Info(ObjectName,
"Keyboard Thread Procedure Entered");
int KeyValue = (int)'a';
while (true)
{
// When this method is called by the
// ServiceObjectThreadHelper, it is obligated to
// exit when the event ThreadStopEvent has been
// set.
if (ThreadStopEvent.WaitOne(2000, false))
{
break;
}
if (KeyValue <= (int) 'z')
{
Logger.Info(ObjectName, "Reader Thread cycling");
// Try to get a strong reference to the Service
// Object using the weak reference saved when
// this helper object was created.
SampleKeyboard Keyboard =
ServiceObjectReference.Target
as SampleKeyboard;
// If this fails, that means the Service Object
// has already been disposed of - exit the thread.
if (Keyboard == null)
{
break;
}
if (Keyboard.DataEventEnabled == true)
{
// Call a method implemented in our Keyboard
// class to queue the key stroke.
Keyboard.SendKey(KeyValue);
// Simulate input by moving through the
// alphabet, sending one character at a time.
KeyValue++;
if (KeyValue >= (int)'z')
{
// Once you run out of input, simulate a
// power state change. Setting the SO's
// PowerState property to
// PowerState.Offline will cause a
// StatusUpdateEvent to be sent to the
// application.
Keyboard.ChangePowerState(
PowerState.Offline);
// Release the strong reference.
Keyboard = null;
// There is no more work, so exit the
// loop.
break;
}
}
// Release the strong reference.
Keyboard = null;
}
}
}
}
#endregion Thread Helper Class
}
編譯程式碼
- 此範例要求包含「 服務物件閱讀緒 介紹」部分的程式碼。
- 必須參考 Microsoft.PointOfService 與 Microsoft.PointOfService.BaseServiceObjects 這兩個組件。