using System; using System.Runtime.InteropServices; using System.Windows.Forms; using Blacklight.Core.Keyboard; namespace Blacklight.Core.UnitTests.Keyboard { public class RawKeyMessageTests : UnitTestSharp.TestFixture { [DllImport("User32.dll")] private static extern bool PostMessage(IntPtr window, uint message, IntPtr wParam, IntPtr lParam); public static IntPtr LParam(int scanCode, bool extended = false, bool repeat = false, bool release = false) { long lParam = 1 | ((long)scanCode << 16); if (extended) { lParam |= 1L << 24; } if (repeat || release) { lParam |= 1L << 30; } if (release) { lParam |= 1L << 31; } return (IntPtr)unchecked((int)lParam); } public static RawKeyMessage Make(int message = RawKeyMessage.KeyDownMessage, int virtualKey = 0x41, int scanCode = 0x1E, bool extended = false, uint time = 100) { bool release = message == RawKeyMessage.KeyUpMessage || message == RawKeyMessage.SysKeyUpMessage; IntPtr lParam = LParam(scanCode, extended, repeat: false, release: release); return RawKeyMessage.From(Message.Create(IntPtr.Zero, message, (IntPtr)virtualKey, lParam), time); } public static RawKeyMessage LeftControl(int message, uint time) { return Make(message, RawKeyMessage.ControlVirtualKey, RawKeyMessage.LeftControlScanCode, time: time); } public static RawKeyMessage RightAlt(int message, uint time) { return Make(message, RawKeyMessage.MenuVirtualKey, scanCode: 0x38, extended: true, time: time); } public class FromTests : UnitTestSharp.TestFixture { public void ReadsTheMessageAndTheVirtualKey() { RawKeyMessage key = Make(RawKeyMessage.SysKeyDownMessage, virtualKey: 0x46); CheckEqual(RawKeyMessage.SysKeyDownMessage, key.Msg); CheckEqual(0x46, key.VirtualKey); } public void ReadsTheScanCode() { CheckEqual(0x2C, Make(scanCode: 0x2C).ScanCode); } public void ReadsTheExtendedBit() { Check(Make(extended: true).IsExtended); CheckFalse(Make(extended: false).IsExtended); } public void ReadsTheRepeatBit() { var repeated = Message.Create(IntPtr.Zero, RawKeyMessage.KeyDownMessage, (IntPtr)0x41, LParam(0x1E, repeat: true)); var first = Message.Create(IntPtr.Zero, RawKeyMessage.KeyDownMessage, (IntPtr)0x41, LParam(0x1E)); Check(RawKeyMessage.From(repeated, 0).IsRepeat); CheckFalse(RawKeyMessage.From(first, 0).IsRepeat); } public void ReleaseIsAlwaysARepeat() { Check(Make(RawKeyMessage.KeyUpMessage).IsRepeat); } public void CarriesTheTimeItWasGiven() { CheckEqual(831281734u, Make(time: 831281734u).Time); } } public class IsDownAndIsUpTests : UnitTestSharp.TestFixture { public void KeyDownAndSysKeyDown_AreDown() { Check(Make(RawKeyMessage.KeyDownMessage).IsDown); Check(Make(RawKeyMessage.SysKeyDownMessage).IsDown); CheckFalse(Make(RawKeyMessage.KeyDownMessage).IsUp); } public void KeyUpAndSysKeyUp_AreUp() { Check(Make(RawKeyMessage.KeyUpMessage).IsUp); Check(Make(RawKeyMessage.SysKeyUpMessage).IsUp); CheckFalse(Make(RawKeyMessage.KeyUpMessage).IsDown); } public void CharacterMessage_IsNeither() { RawKeyMessage key = Make(message: 0x0102); CheckFalse(key.IsDown); CheckFalse(key.IsUp); } } public class SlotTests : UnitTestSharp.TestFixture { public void ExtendedAndPlainKeysWithOneScanCode_Differ() { CheckFalse(Make(scanCode: 0x1D, extended: true).Slot == Make(scanCode: 0x1D, extended: false).Slot); } public void DifferentScanCodes_Differ() { CheckFalse(Make(scanCode: 0x1E).Slot == Make(scanCode: 0x1F).Slot); } public void PressAndRelease_Match() { CheckEqual(Make(RawKeyMessage.KeyDownMessage, scanCode: 0x1E).Slot, Make(RawKeyMessage.KeyUpMessage, scanCode: 0x1E).Slot); } } public class IsLeftControlTests : UnitTestSharp.TestFixture { public void ControlAtTheLeftScanCode_IsLeftControl() { Check(LeftControl(RawKeyMessage.KeyDownMessage, time: 1).IsLeftControl); } public void ExtendedControl_IsNot() { CheckFalse(Make(virtualKey: RawKeyMessage.ControlVirtualKey, scanCode: 0x1D, extended: true) .IsLeftControl); } public void OtherVirtualKeyAtThatScanCode_IsNot() { CheckFalse(Make(virtualKey: 0x41, scanCode: 0x1D).IsLeftControl); } public void ControlAtAnotherScanCode_IsNot() { CheckFalse(Make(virtualKey: RawKeyMessage.ControlVirtualKey, scanCode: 0x1E).IsLeftControl); } } public class ToKeyCodeTests : UnitTestSharp.TestFixture { public void UsesTheScanCode() { CheckEqual(KeyCode.W, Make(virtualKey: 0x41, scanCode: 0x11).ToKeyCode().Value); } public void UsesTheExtendedBit() { CheckEqual(KeyCode.ControlRight, Make(scanCode: 0x1D, extended: true).ToKeyCode().Value); } public void NoScanCode_FallsBackToTheVirtualKey() { CheckEqual(KeyCode.Tab, Make(virtualKey: 0x09, scanCode: 0).ToKeyCode().Value); } public void NoScanCodeAndNoKnownVirtualKey_IsNull() { CheckNull(Make(virtualKey: 0xFF, scanCode: 0).ToKeyCode()); } public void UnmodelledScanCode_IsNull() { CheckNull(Make(scanCode: 0x56).ToKeyCode()); } } public class ToLayoutCodeTests : UnitTestSharp.TestFixture { public void Letters_MapToTheirLetterKeyCode() { for (char letter = 'A'; letter <= 'Z'; letter++) { var expected = (KeyCode)Enum.Parse(typeof(KeyCode), letter.ToString()); CheckEqual(expected, Make(virtualKey: letter).ToLayoutCode().Value); } } public void TopRowDigits_MapToTheirDigitKeyCode() { for (char digit = '0'; digit <= '9'; digit++) { var expected = (KeyCode)Enum.Parse(typeof(KeyCode), "Digit" + digit); CheckEqual(expected, Make(virtualKey: digit).ToLayoutCode().Value); } } public void KeypadDigits_AreNull() { for (int virtualKey = 0x60; virtualKey <= 0x69; virtualKey++) { CheckNull(Make(virtualKey: virtualKey).ToLayoutCode()); } } public void VirtualKeysBesideTheLettersAndDigits_AreNull() { CheckNull(Make(virtualKey: 0x2F).ToLayoutCode()); CheckNull(Make(virtualKey: 0x3A).ToLayoutCode()); CheckNull(Make(virtualKey: 0x40).ToLayoutCode()); CheckNull(Make(virtualKey: 0x5B).ToLayoutCode()); } public void NamedAndPunctuationKeys_AreNull() { CheckNull(Make(virtualKey: 0x20).ToLayoutCode()); CheckNull(Make(virtualKey: 0x0D).ToLayoutCode()); CheckNull(Make(virtualKey: 0x70).ToLayoutCode()); CheckNull(Make(virtualKey: 0xBA).ToLayoutCode()); CheckNull(Make(virtualKey: RawKeyMessage.ProcessKeyVirtualKey).ToLayoutCode()); } } public class IsAltGrControlTests : UnitTestSharp.TestFixture { public void PressFollowedByRightAltPressAtTheSameTime_IsFake() { RawKeyMessage current = LeftControl(RawKeyMessage.KeyDownMessage, time: 50); RawKeyMessage next = RightAlt(RawKeyMessage.SysKeyDownMessage, time: 50); Check(RawKeyMessage.IsAltGrControl(current, next)); } public void ReleaseFollowedByRightAltReleaseAtTheSameTime_IsFake() { RawKeyMessage current = LeftControl(RawKeyMessage.KeyUpMessage, time: 50); RawKeyMessage next = RightAlt(RawKeyMessage.KeyUpMessage, time: 50); Check(RawKeyMessage.IsAltGrControl(current, next)); } public void NothingBehindIt_IsReal() { CheckFalse(RawKeyMessage.IsAltGrControl(LeftControl(RawKeyMessage.KeyDownMessage, 50), null)); } public void RightAltAtAnotherTime_IsReal() { RawKeyMessage current = LeftControl(RawKeyMessage.KeyDownMessage, time: 50); RawKeyMessage next = RightAlt(RawKeyMessage.KeyDownMessage, time: 51); CheckFalse(RawKeyMessage.IsAltGrControl(current, next)); } public void LeftAltBehindIt_IsReal() { RawKeyMessage current = LeftControl(RawKeyMessage.KeyDownMessage, time: 50); RawKeyMessage next = Make(RawKeyMessage.KeyDownMessage, RawKeyMessage.MenuVirtualKey, scanCode: 0x38, extended: false, time: 50); CheckFalse(RawKeyMessage.IsAltGrControl(current, next)); } public void OtherKeyBehindIt_IsReal() { RawKeyMessage current = LeftControl(RawKeyMessage.KeyDownMessage, time: 50); RawKeyMessage next = Make(RawKeyMessage.KeyDownMessage, virtualKey: 0x41, extended: true, time: 50); CheckFalse(RawKeyMessage.IsAltGrControl(current, next)); } public void PressFollowedByARelease_IsReal() { RawKeyMessage current = LeftControl(RawKeyMessage.KeyDownMessage, time: 50); RawKeyMessage next = RightAlt(RawKeyMessage.KeyUpMessage, time: 50); CheckFalse(RawKeyMessage.IsAltGrControl(current, next)); } public void CharacterMessageBehindIt_IsReal() { RawKeyMessage current = LeftControl(RawKeyMessage.KeyDownMessage, time: 50); RawKeyMessage next = Make(message: 0x0102, virtualKey: RawKeyMessage.MenuVirtualKey, scanCode: 0x38, extended: true, time: 50); CheckFalse(RawKeyMessage.IsAltGrControl(current, next)); } public void RightControl_IsNeverFake() { RawKeyMessage current = Make(virtualKey: RawKeyMessage.ControlVirtualKey, scanCode: 0x1D, extended: true, time: 50); RawKeyMessage next = RightAlt(RawKeyMessage.SysKeyDownMessage, time: 50); CheckFalse(RawKeyMessage.IsAltGrControl(current, next)); } } public class PeekNextTests : UnitTestSharp.TestFixture { public void EmptyQueue_IsNull() { using (var control = new Control()) { CheckNull(RawKeyMessage.PeekNext(control.Handle)); } } public void QueuedKeyMessage_IsReadWithoutRemovingIt() { using (var control = new Control()) { PostMessage(control.Handle, RawKeyMessage.SysKeyDownMessage, (IntPtr)RawKeyMessage.MenuVirtualKey, LParam(0x38, extended: true)); RawKeyMessage? first = RawKeyMessage.PeekNext(control.Handle); RawKeyMessage? second = RawKeyMessage.PeekNext(control.Handle); CheckEqual(RawKeyMessage.MenuVirtualKey, first.Value.VirtualKey); Check(first.Value.IsExtended); CheckEqual(first.Value.Time, second.Value.Time); } } public void MessageForAnotherWindow_IsNotSeen() { using (var queued = new Control()) using (var other = new Control()) { PostMessage(queued.Handle, RawKeyMessage.KeyDownMessage, (IntPtr)0x41, LParam(0x1E)); CheckNull(RawKeyMessage.PeekNext(other.Handle)); } } } } }