I'm setting up mouse gestures in my xmonad.hs, and I'd like to avoid using a modMask modifier to get keyboard-free gestures. Problem is, there are cases (e.g. empty gesture, just a simple click) where I'd like to let the mouse event go through to the application under the cursor, but I haven't found a way to do that in XMonad. Without that, if i add ((0, button3), mouseGesture gestures), i completely lose the "application-specific" functionality of button3.
I was thinking that, if the events cannot be easily forwarded, perhaps a new one can be created and dispatched. I thought about using spawn "xdotool click 3" but it doesn't seem to work. Has anybody ever tried something similar? Otherwise, I'd need a mouse with at least 4 buttons, since most apps actively use three...
To get xdotool to forward your mouse clicks, you need to make sure that it targets the correct window using the --window parameter. For example, if your window id is 79693135, then xdotool click --window 79693135 3 does exactly what you want.
The following basic xmonad.hs illustrates how to do this in order to get keyboardless mouse gestures working properly:
import XMonad
import qualified XMonad.Actions.CycleWS as Workspace
import XMonad.Actions.MouseGestures ( mouseGesture, Direction2D(..) )
import qualified XMonad.Util.EZConfig as EZ
import XMonad.Util.Run ( safeSpawn )
import qualified Data.Map as Map
mouseGestureButton :: Button
mouseGestureButton = button3 -- right click
sendMouseClickToWindow :: Window -> X ()
sendMouseClickToWindow win =
safeSpawn
"xdotool" ["click", "--window", show win, show mouseGestureButton]
myMouseGestures :: [([Direction2D], Window -> X ())]
myMouseGestures =
[ ([R], const Workspace.nextWS) -- move to the next workspace
, ([L], const Workspace.prevWS) -- move to the previous workspace
, ([], sendMouseClickToWindow)
]
addMouseGestures :: XConfig a -> XConfig a
addMouseGestures =
flip EZ.additionalMouseBindings
[((0, mouseGestureButton), mouseGesture $ Map.fromList myMouseGestures)]
main = xmonad $ addMouseGestures def
N.B.: It's not a good idea to use button 1 for this, because that will interfere with selecting text and other mouse-dragging functionality normally used with button 1. So using button 3 (as the OP did) is definitely the right idea.
Related
I need to run a custom action when my marker is clicked.
I tried, according to tutorial,
NavigationGutterIconBuilder<PsiElement> builder =
NavigationGutterIconBuilder.create(LessonScriptIcons.PUZZLE).
setTarget(this).
setTooltipText("Navigate to component");
RelatedItemLineMarkerInfo<PsiElement> m = builder.createLineMarkerInfo(this);
But I can't figure out how to get to the marker's navigation handler, or otherwise listen to this marker's events. (The cursor moving to the beginning of "this" element is a slightly undesired, but unimportant side effect that would be nice to suppress).
Then I tried this:
RelatedItemLineMarkerInfo marker = new RelatedItemLineMarkerInfo(this, getTextRange(), MyIcons.VOLUME, 0, tooltipProvider, handler, GutterIconRenderer.Alignment.CENTER, new ArrayList<GotoRelatedItem>());
This approach allows me to listen to the marker's mouse clicks. However, now I am experiencing a peculiar problem: whenever the marked line of code is edited, this results in duplicate, triplicate, etc. markers in the gutter.
What's the correct way to do it?
Turns out I needed to specify a pass.
int pass = Pass.UPDATE_OVERRIDEN_MARKERS;
RelatedItemLineMarkerInfo marker = new RelatedItemLineMarkerInfo(this, getTextRange(), MyIcons.VOLUME, pass, tooltipProvider, handler, GutterIconRenderer.Alignment.CENTER, new ArrayList<GotoRelatedItem>());
I had to use Pass.UPDATE_OVERRIDEN_MARKERS even though IntelliJ marked it as deprecated and said it will be removed shortly (see the link below). However, the constant recommended by IntelliJ, Pass.LINE_MARKERS, results in duplicate markers.
https://github.com/JetBrains/intellij-community/blob/master/platform/analysis-impl/src/com/intellij/codeHighlighting/Pass.java
I found no references about this in the documentation.
You cannot easily style this "extension" button because that symbol is actually an icon.
You can however access the QToolButton widget to set the icon to whatever you like. In PyQt4 you get to it with menubar.children()[0]. This should be consistent with PyQt5. Looking at the Qt5 source code, it appears that the extension icon is always created first, even if it is not shown, and the children() method returns objects in the order in which they were created (this the index of 0).
Once you have a reference to the QToolButton, you can then set the icon to whatever you like with menubar.children()[0].setIcon(my_qicon) (or similar).
Since this is one of the top items on google for modifying the "show more" icon:
Another option is to use a QToolbar. You can do the same thing except that the first child is a layout, second is the QToolButton that you want:
from qtpy import QtWidgets, QtGui
import sys
def call_back():
print('pressed')
app = QtWidgets.QApplication([])
widget = QtWidgets.QWidget()
layout = QtWidgets.QGridLayout(widget)
toolbar = QtWidgets.QToolBar()
layout.addWIdget(toolbar)
# add some actions
for i in range(10):
toolbar.addAction('test_{}'.format(i), call_back)
# change the icon, the first child is a layout!, the second it the toolbtn we want!
toolbar.children()[1].setIcon(QtGui.QIcon('path/to/image.png'))
widget.show()
app.exec_()
sys.exit()
I am trying to automate IE11 notification bar ( while downloading file) using Rautomation. Using MSUIA adapter I am able to catch the the save button. But I want to use Save As to supply the file location and name. But I cannot do that.
When seeing with UIspy I see that there is a splitbutton with name "Save". This splitbutton has another child splitbutton with name "" ( which is basically the down arrow) - I am not able to get to this control.
iemainwindow_local = RAutomation::Window.new(:class=>"IEFrame" , :adapter => :ms_uia )
ienotificationbar_frame = iemainwindow_local.child(:class=>"Frame Notification Bar")
ienotificationbar = ienotificationbar_frame.child(:class=>"DirectUIHWND")
if ienotificationbar.exists?
ienotificationbar.activate
sleep 1
mycontrol = ienotificationbar.control(:value =>"Save")
mycontrol2= mycontrol.control(:children_only => true)
mycontrol2.exist?
mycontrol.click
end
Getting error at this line mycontrol2= mycontrol.control(:children_only => true)
undefined method `control' for #<RAutomation::Adapter::MsUia::Control:0x4108e60>
Any idea how to get over this block?
I understand that there should be a menu and menuitems associated with the splitButton and when I click on down arrow besides Save, at UISpy I see that menu/ menu item is getting created directly under Desktop window ( though the processID is same ) - how to catch the menuitem Save as?
The Problem
Unfortunately, the :ms_uia adapter for RAutomation is not able to do this in its current form. I know this because I have written a lot of the UIA adapter for it :) The problem is that the current API doesn't allow you to really walk the tree like that (as you found out) because the Control class doesn't have a #control method. If the "Save" button had a native window handle, you'd be able to do this:
ieframe = RAutomation::Window.new(class: 'IEFrame')
save = RAutomation::Window.new(hwnd: ieframe.control(value: 'Save').hwnd)
save.control(index: 0)
Since it does not, unfortunately there isn't a reliable way to get down to it that I am aware of since it doesn't have any identifying properties about it (other than being a child of the "Save" button).
Alternative
I've written another gem called uia, which acts as a low-level wrapper around UI Automation and allows you to work more closely with UI Automation and interact with it how you see it within tools like UI Spy. Eventually, I will use this gem in RAutomation but have not had the time yet. To get down to the "Save As..." split button control in your circumstance, you can do this:
ieframe = UIA.find_element(title: /Thanks for downloading/)
save_as = ieframe.find(name: 'Save').find(control_type: :split_button)
save_as.as(:invoke).invoke
The save_as.as(:invoke) will treat the found "Save As" Element as something that implements the Invoke pattern, and then you can call the #invoke method to get the menu to pop.
Hope this helps!
Using Rebol/View 2.7.7, I'm trying to create a card game based on Nick's Rebol tutorial at: http://re-bol.com/rebol.html#section-10.18. What I want to do though is read the cards from the binary file Nick created, discard some of the data, and use it to layout a tableau of cards, 4 rows of 3 columns, with the 2 center card locations not used.
Here's my code:
protect-system
random/seed now
do %cards.r ;--include the binary card data
the-tableau: [
size 320x480 backdrop 0.170.0
style tabstyle image 80x100 teal
style holdplace box 80x100 coal
across
at 30x20 tc1: tabstyle
tc2: tabstyle
tc3: tabstyle return
at 30x130 tc4: tabstyle
tc100: holdplace
tc5: tabstyle return
at 30x240 tc6: tabstyle
tc200: holdplace
tc7: tabstyle return
at 30x350 tc8: tabstyle
tc9: tabstyle
tc10: tabstyle
]
lc: copy []
lc: [tc1 tc2 tc3 tc4 tc5 tc6 tc7 tc8 tc9 tc10]
deck-cards: copy [] ; The deck holds all of the cards from the binary file
deck-cards-num: copy []
deck-cards-color: copy []
lay: layout the-tableau
foreach [card label num color pos] cards [
dimg: load to-binary decompress (card)
append deck-cards dimg ;feel movestyle
throw-away-label: label
append deck-cards-num num
append deck-cards-color color
throw-away-pos: pos
]
random-card: does [pick deck-cards random length? deck-cards]
foreach c lc [set-face get c deck-cards]
view lay
do-events
But this doesn't show the cards at all. I'm not even sure it's reading the correctly? Where is the problem?
Actually you didn't use the random-card function in your for loop at the end... :-)
foreach c lc [get c set-face get c random-card ]
You note that you are not sure if data was loaded correctly...
here is a simple way to find out... just print/probe the TYPE? of that data
dimg: load to-binary decompress (card)
probe type? dimg
In this case it will print out image! in the console... so yep... that's working. :-)
As an added little detail, I noticed you didn't compensate your random for the "back face" image in the card data (which is at its end), so the random-card function should be fixed like so:
random-card: does [pick deck-cards random (length? deck-cards) - 1] ; - 1 since we don't want the back face to be picked.
You only need 'do-events if the event loop is not started.
View/new does not start the event loop .. but View does
I'm not addressing your actual problem though :(
to make the do-events note clear, I added a little answer here so I can add some inline code....
here is an example where you'd want your do-events to be used.
view/new lay ; display the interface right now. (with no cards)
random-card: does [pick deck-cards random (length? deck-cards) - 1] ; - 1 since we don't want the back face to be picked.
; deal cards with a half second delay.
foreach c lc [f: get c set-face get c random-card wait 0.5]
do-events
here, any code you put after 'DO-EVENTS will be executed once all view windows have closed.
which can be things like tmp file cleanup, save on exit, "save changes" dialogs, etc.
additional note:
While building graphics code, its a good habit to place this at the very start of you application:
print " "
It will open up the console, and then any view windows will show up in front of it.
When ready to share, just comment the line and remove any print statements in your code.
this is useful for 3 things:
1) Its usually highly annoying when the console always pops-up over your application while its tracing (print/probe/etc) some stuff after your window opens.
2) This also has the more useful side-effect of showing you if your application quit correctly since the console will ALSO quit when all waits have terminated correctly.
In your original example, if you add the above print, then you'll see that the console never closes, so this means the application is still running with no more application windows listening to events.
3) It also has the advantage that you can terminate the graphic app directly by closing the console window. This effectively closes all windows and waits immediately and shortcuts any "on application quit" code you might have (code after do-events).
I've had nothing but grief using Symbian's browser control on S60 3rd edition FP1. We currently display pages and many things are working smoothly. However, when inputting text into an HTML text field, the user will get a KERN-EXEC 3 if they move left at the beginning of the text input area (which should "wrap" it to the end) or if they move right at the end of the text input area (which should "wrap" it to the beginning).
I can't seem to trap the input in OfferKeyEventL. I get the key event, I return EKeyWasConsumed and the cursor still moves.
TKeyResponse CMyAppContainer::OfferKeyEventL(const TKeyEvent& aKeyEvent, TEventCode aType)
{
if (iBrCtlInterface) // My browser control
{
TBrCtlDefs::TBrCtlElementType type = iBrCtlInterface->FocusedElementType();
if (type == TBrCtlDefs::EElementActivatedInputBox || type == TBrCtlDefs::EElementInputBox)
{
if (aKeyEvent.iScanCode == EStdKeyLeftArrow || aKeyEvent.iScanCode == EStdKeyRightArrow)
{
return EKeyWasConsumed;
}
}
}
}
I would be okay with completely disabling arrow key navigation but can't seem to do this.
Any ideas? Am I going about this the wrong way? Has anyone here even worked with the Browser Control library (browserengine.lib) on S60 3.1?
Update: Interestingly, if I switch to use Cursor Navigation, it works fine. For now, this is a workaround. I'm still curious to know if there are ways to resolve this.
You would get quicker answer probably in http://discussion.forum.nokia.com/forum/.
Interestingly, if I switch to use Cursor Navigation, it works fine. For now, this is a workaround. I'm still curious to know if there are ways to resolve this. For now, I'm calling this the answer.