Issue #134: Added generic implementation of `#sendKeyOrButtonEvent:..` to `DeviceWorkstation`
...as a fallback. This implementation works purely on a
Smalltalk level by directly injecting (St/X) events in
(St/X) window group's event queue, completely bypassing
windowing system.
The implementation is icomplete and is designed and tested
only with UI testing framework (stx:goodies/sunit/ext/ui)
to allow UI testing on systems with no specific implementation
of `#sendKeyOrButtonEvent...` - e.g. Windows at the time.
https://swing.fit.cvut.cz/projects/stx-jv/ticket/134
--- a/DeviceWorkstation.st Tue Apr 25 11:20:05 2017 +0200
+++ b/DeviceWorkstation.st Sat May 06 11:26:33 2017 +0100
@@ -5168,7 +5168,49 @@
The non-nil case is the lowlevel entry, where state must include any shift/ctrl information
(not very user friendly)"
- self subclassResponsibility
+ "/ WARNING: this is a generic implementation that completely bypasses underlaying
+ "/ system event queue. It may not be complete - it has been written as a quick hack
+ "/ to make UI testing framework kind-of working on systems where there's no proper
+ "/ implementation of this method (e.g., Windows at the time)
+
+ | view shiftWasDown ctrlWasDown altWasDown metaWasDown |
+
+ view := self viewFromId: targetId.
+
+ [
+ shiftWasDown := shiftDown.
+ altWasDown := altDown.
+ metaWasDown := metaDown.
+ ctrlWasDown := ctrlDown.
+ stateMask notNil ifTrue:[
+ shiftDown := (stateMask bitAnd: self shiftModifierMask) ~~ 0.
+ altDown := (stateMask bitAnd: self altModifierMask) ~~ 0.
+ metaDown := (stateMask bitAnd: self metaModifierMask) ~~ 0.
+ ctrlDown := (stateMask bitAnd: self ctrlModifierMask) ~~ 0.
+ ].
+ (typeSymbol == #keyPress or:[ typeSymbol == #keyRelease ]) ifTrue:[
+ | key |
+
+ key := keySymCodeOrButtonNr.
+ (#(Left Right Up Down) includes: key) ifTrue:[
+ key := (#Cursor , key) asSymbol.
+ ].
+ typeSymbol == #keyPress ifTrue:[
+ self keyPress:key x:1 y:1 view:view.
+ ] ifFalse:[
+ self keyRelease:key x:1 y:1 view:view.
+ ]
+ ] ifFalse:[
+ self notYetImplemented.
+ ].
+ ] ensure:[
+ shiftDown := shiftWasDown.
+ altDown := altWasDown.
+ metaDown := metaWasDown.
+ ctrlDown := ctrlWasDown.
+ ].
+
+ "Modified (comment): / 06-05-2017 / 11:15:25 / jv"
!
simulateKeyboardInput:aCharacterOrString inViewId:viewId
--- a/WinWorkstation.st Tue Apr 25 11:20:05 2017 +0200
+++ b/WinWorkstation.st Sat May 06 11:26:33 2017 +0100
@@ -19,7 +19,7 @@
classVariableNames:'BeepDuration NativeDialogs NativeFileDialogs NativeWidgets
NativeWidgetClassTable StandardColorValues IgnoreSysColorChanges
IgnoreFontChanges SystemColorValues CanEndSession
- VerboseNativeDialogs '
+ VerboseNativeDialogs'
poolDictionaries:''
category:'Interface-Graphics'
!
@@ -6495,7 +6495,7 @@
' Peak User Objects = ' errorPrint. counts second errorPrintCR.
' # GDI Objects = ' errorPrint. counts third errorPrintCR.
' Peak GDI Objects = ' errorPrint. counts fourth errorPrintCR.
-!
+!
printHandleCounts
"show prim values"
@@ -8090,55 +8090,6 @@
"Modified: / 28-01-2012 / 10:20:30 / cg"
!
-destroyGC:aGCId
-%{
- if (__isExternalAddress(aGCId)) {
- struct gcData *gcData = _GCDATA(aGCId);
-
- if (gcData == NULL) {
- console_fprintf(stderr, "WinWorkstation [warning]: trying to destroy GC twice\n");
- RETURN(self);
- }
-
-#ifdef COUNT_RESOURCES
- __cnt_gcData--;
- RESPRINTF(("DestroyGcData %d\n",__cnt_gcData));
-#endif
-
-#ifdef CACHE_LAST_DC
- if (lastGcData == gcData) {
- _releaseDC(gcData);
- }
-#endif
- __ExternalAddressInstPtr(aGCId)->e_address = NULL;
-
- freeGcData(gcData);
- }
-%}
-!
-
-destroyPixmap:aDrawableId
-
-%{ /* NOCONTEXT */
- if (__isExternalAddress(aDrawableId) && ISCONNECTED) {
- HANDLE bitmapHandle = _HANDLEVal(aDrawableId);
-
- if (bitmapHandle) {
-#ifdef COUNT_BMP_RESOURCES
- __cnt_bitmap--;
- RES_BMP_PRINTF(("DestroyPixmap %x %d\n", bitmapHandle, __cnt_bitmap));
-#endif
- _DeleteObject(bitmapHandle, __LINE__);
- }
- }
-%}
-!
-
-destroyView:aView withId:aWindowId
- self primDestroyView:aView withId:aWindowId.
- self removeKnownView:aView withId:aWindowId
-!
-
dcGetClipBoxForGC: gcId
"Return clipping box for given device context (as #(left top right bottom) ). "
@@ -8201,7 +8152,7 @@
err:;
%}.
^ self primitiveFailed: error
-!
+!
dcUnlockForGC:gcId
"Unlocks and __destroy__ a device context for given GC previously
@@ -8224,7 +8175,56 @@
err:;
%}.
^ self primitiveFailed: error
-!
+!
+
+destroyGC:aGCId
+%{
+ if (__isExternalAddress(aGCId)) {
+ struct gcData *gcData = _GCDATA(aGCId);
+
+ if (gcData == NULL) {
+ console_fprintf(stderr, "WinWorkstation [warning]: trying to destroy GC twice\n");
+ RETURN(self);
+ }
+
+#ifdef COUNT_RESOURCES
+ __cnt_gcData--;
+ RESPRINTF(("DestroyGcData %d\n",__cnt_gcData));
+#endif
+
+#ifdef CACHE_LAST_DC
+ if (lastGcData == gcData) {
+ _releaseDC(gcData);
+ }
+#endif
+ __ExternalAddressInstPtr(aGCId)->e_address = NULL;
+
+ freeGcData(gcData);
+ }
+%}
+!
+
+destroyPixmap:aDrawableId
+
+%{ /* NOCONTEXT */
+ if (__isExternalAddress(aDrawableId) && ISCONNECTED) {
+ HANDLE bitmapHandle = _HANDLEVal(aDrawableId);
+
+ if (bitmapHandle) {
+#ifdef COUNT_BMP_RESOURCES
+ __cnt_bitmap--;
+ RES_BMP_PRINTF(("DestroyPixmap %x %d\n", bitmapHandle, __cnt_bitmap));
+#endif
+ _DeleteObject(bitmapHandle, __LINE__);
+ }
+ }
+%}
+!
+
+destroyView:aView withId:aWindowId
+ self primDestroyView:aView withId:aWindowId.
+ self removeKnownView:aView withId:aWindowId
+!
gcFor:aDrawableId
@@ -13171,8 +13171,9 @@
The non-nil case is the lowlevel entry, where state must include any shift/ctrl information
(not very user friendly)"
- 'WinWorkstation [warning]: sendKeyOrButtonEvent unimplemented' infoPrintCR.
- ^ false
+ super sendKeyOrButtonEvent:typeSymbol x:xPos y:yPos keyOrButton:keySymCodeOrButtonNr state:stateMask toViewId:targetId
+
+ "Modified: / 06-05-2017 / 11:19:03 / jv"
! !
!WinWorkstation methodsFor:'font stuff'!
@@ -19612,6 +19613,11 @@
version_CVS
^ '$Header$'
+!
+
+version_HG
+
+ ^ '$Changeset: <not expanded> $'
! !