AutoHotkey Homepage AutoHotkey Community
Let's help each other out
 
 FAQFAQ   SearchSearch   MemberlistMemberlist   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

Simple Mouse Gesture and Rocker
Goto page 1, 2, 3, 4, 5, 6, 7, 8  Next
 
Reply to topic    AutoHotkey Community Forum Index -> Scripts & Functions
View previous topic :: View next topic  
Author Message
rodfell



Joined: 05 Oct 2007
Posts: 138
Location: Bundaberg (Bundy), Qld, Australia

PostPosted: Tue Nov 06, 2007 12:18 pm    Post subject: Simple Mouse Gesture and Rocker Reply with quote

Simple Mouse Gesture and Rocker

Latest version is posted here.

Simple Mouse Gesture and Rocker calls subroutines based on either gestures made when the right(r), middle(m), 4th(x1) or fifth(x2) mouse button is held down; when a rocking action is made using these mouse buttons, or a combination of the two.
The script tracks up (u) down (d) left (l) right (r). There is a tolerance of +/- 35 degrees, so it is quite simple and accurate

Subroutines will be called if labelled with the following syntax:

"m-" is the prefix (m for macro)

the next letter is the mouse button that starts the gesture eg m-r: is a gesture that starts with a right click

If the first mouse button (say RButton) remains down and a different mouse button (say LButton) is pressed, the second button is added. eg m-rl:

If a gesture is made, say up then right (ur), the gesture is enclosed in parentheses eg m-r(ur):

gestures and rocking can be combined eg m-rl(u):

Modifier keys - alt(!), ctrl(^) and shift(+) can be used eg m-^r: or m-!-wheeldown:

for simplicity and accuracy, right click-gesture-left click is the same as right click-left click-gesture

With wheel movements, -wheelup or -wheeldown is appended - eg m-r(u)-wheelup:

If the wheel is used, no further gesturing or rocking is allowed (to avoid movement errors). wheel movements can be repeated while the mouse button is held down

Another thing that isn't allowed is gesturing solely with the LButton (so as not to interfere with mouse dragging). The LButton however is registered when other mouse buttons or the mouse wheel are pressed eg m-rl(u): ; m-l-wheelup:

Middle button clicking is difficult if combined with mouse wheel movements. If one is used the other is blocked.This protection can be turned off by making line 3 "wheelguard:=false"

When rocking, the last button clicked can be repeadedly clicked while the other buttons are kept down. also, A different button can be called
eg m-rl can be changed to m-rm or m-rx or if the right button is kept down

You can rock with more than 2 buttons at a time eg m-rlx

By not allowing diagonals, gestures can be drawn without abrupt angles. eg a circle drawn from the top and clockwise is registered as m-r(rdlu): (right down left up)
if a right mouse button gesture is down (d) and right (r), like an "L", a subroutine called m-r(dr): (for gesture with right mouse button, tracking down then right) will be called
the script also pays attention to the window under the gesture and notes if the gesture is made over the desktop

Thanks for any ideas gathered from other gesture programs, especially lexicos

Code:
demomode:=true    ;demonstration mode on/off. change to false when ready to use
mintrack=20       ;minimum length of registered track sector in pixels 
wheelguard:=true  ;if true, wheel and middle button click can't both be used in the same gesture (recommended)

#MaxHotkeysPerInterval 500  ;prevents problems with rapid wheel movements
winget,windesktop,id,ahk_class Progman   ;desktop id, useful for some macros
gosub cleanup

*mbutton::   ;list any mouse buttons that can be uniquely named by first letter here eg. *mbutton is "m"
*lbutton::   ;the asterisk allows for the use of modifier keys   
*rbutton::     
*xbutton1::
*xbutton2::
lastdown:=thishotkey()
if macrorunning or wheel
   return
if not buttonsdown
   {
   mousegetpos xpos1,ypos1,win1  ;win1 is the window underneath the current gesture
   modifier:=(getkeystate("alt","p") ? "!" : "") . (getkeystate("shift","p") ? "+" : "") . (getkeystate("ctrl","p") ? "^" : "")
   settimer,tracking,1
   }
mouseclick:=buttonsdown.=(not buttonsdown and getkeystate("lbutton","p") ? "l" : "") . lastdown
winget,winactive,id,A          ;active window id, useful for some macros
sendinput {lbutton up}         ;prevents drag box appearing when left/right rocking and gesturing eg. m-lr(d):
hotkey,*lbutton,on             ;*lbutton only tracked when other mouse buttons start tracking
hotkey,*lbutton up,on
return

*mbutton up::
if wheel and wheelguard        ;middle button clicks ignored when using wheel (if wheelguard=true)
   return
*rbutton up::
*lbutton up::
*xbutton1 up::
*xbutton2 up::
lastup:=thishotkey()
stringreplace,buttonsdown,buttonsdown,%lastup%,,all
buttonsup:=true
settimer,tracking,off            ;no more gesture tracking once a mouse button has been released
if not wheel and (lastdown=lastup)
   gosub callmacro   
if not buttonsdown         
   gosub cleanup
return

*wheelup::
*wheeldown::
if (instr(buttonsdown,"m") and wheelguard) or macrorunning    ;prevents accidental use of mousewheel with middle button gestures   
   return
if not buttonsdown and getkeystate("lbutton","p")
   {
   mouseclick:=buttonsdown:="l"
   hotkey,*lbutton up,on
   }
if (buttonsdown and not buttonsup) or modifier
   {
   stringtrimleft,wheel,a_thishotkey,1     
   settimer,tracking,off   ;no more tracking once wheel used
   goto callmacro
   }
stringtrimleft,thishotkey,a_thishotkey,1
if not buttonsdown
   sendinput {%thishotkey%}
return
     
callmacro:
macrorunning:=true
macro:="m-" . modifier . mouseclick . (tracking ? "(" . tracking . ")" : "") . (wheel ? "-" . wheel : "")
if (demomode and macro<>"m-r" and macro<>"m-m")
   msgbox,,DEMO MODE,%macro% ,1   
else
   if islabel(macro)         
         gosub %macro%
macrorunning:=false
return

cleanup:
if (win1<>windesktop)     
   win2:=win1     ; used in some gestures, win2 is the window the previous macro acted on
hotkey,*lbutton,off             ; restore normal left mouse button function
hotkey,*lbutton up,off
wheel:="",tracking="",buttonsup="",buttonsdown="",mouseclick="",track2="",modifier=""
return

tracking:
mousegetpos xpos2,ypos2
angle:=abs((xpos1-xpos2)/(ypos1-ypos2+0.001))      ;+0.001 avoids divide by zero error
if (angle>0.7 and angle<1.428) or (abs(ypos1-ypos2)<5 and abs(xpos1-xpos2)<5)   ;ignores angles within 10 degrees of 45 degree diagonal
   return                                                                       ;ignores movement that is too slow
track1:=(abs(ypos1-ypos2)>abs(xpos1-xpos2)) ? (ypos1>ypos2 ? "u" : "d") : (xpos1>xpos2 ? "l" : "r")  ;determines up down left right
if (track1<>track2)            ;remembers mouse position when track direction changes
   xpos_tack:=xpos2,ypos_tack:=ypos2
if (track1<>SubStr(tracking, 0, 1)) and (track1=track2) and (abs(xpos_tack-xpos2)>=mintrack or abs(ypos_tack-ypos2)>=mintrack)
   tracking.=track1        ;track if x or y changing sufficient to register. track needs confirmation (2 tracks same direction)
xpos1:=xpos2,ypos1:=ypos2,track2:=track1
return

thishotkey()   ;eg reduces "xbutton1 up" to "x1"
{
stringreplace,thishotkey,a_thishotkey,*,,all
stringreplace,thishotkey,thishotkey,%a_space%up,,all
stringreplace,thishotkey,thishotkey,button,,all
return thishotkey
}

esc::exitapp

m-r:                     ;normal right click
sendinput {rbutton}
return

m-m:                 ;normal middle click (optional)         
sendinput {mbutton}
return

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;;;;;;; Examples ;;;;;;;;;;;;;;;;;;;;;;;;;;

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;;;;; wheel examples ;;;;;;;;;;

m-r-wheelup:      ;change volume with wheel -  hold right button down and use wheel
Send {Volume_Up}
return

m-r-wheeldown:
Send {Volume_Down}
return

;;;;;;;; rocker examples ;;;;;;;;;;

m-rl:
msgbox,,,if you keep right held down, clicking left will repeat action,5
return

m-lr:                                           
msgbox,,,rocker left then right.,5  ;left click will also fire so some macros not suitable
return                ;can be used for browser forward if you don't click over hypertext

m-rl(l):
m-lr(l):
msgbox,,,you combined rocking and gesturing,5
return

;;;;;;;;;;;; gesture examples ;;;;;;;;;;

m-r(u):             ;; gesture up ;; maximize window under cursor. maximize last window if cursor over desktop
if (win1=windesktop)
   {
   if (win2<>"")
   winmaximize, ahk_id %win2%
   }
else
   winmaximize ahk_id %win1%
return

m-r(d):            ;minimize window under cursor
if (win1<>windesktop)    ;don't minimize the desktop
   winminimize, ahk_id %win1%
return

m-r(l):            ;browser back
winactivate ahk_id %win1%   
sendinput {Browser_Back}
return

m-r(r):            ;browser forward
winactivate ahk_id %win1%   
sendinput {Browser_Forward}
return

m-r(dr):            ;restore last window.
winrestore ahk_id %win2%
return

m-r(ldr):            ;close window under cursor (draw a C)
if (win1<>windesktop)
   winclose ahk_id %win1%
return


Last edited by rodfell on Wed May 11, 2011 11:25 am; edited 119 times in total
Back to top
View user's profile Send private message
ManaUser



Joined: 24 May 2007
Posts: 1121

PostPosted: Tue Nov 06, 2007 9:24 pm    Post subject: Reply with quote

Nice! It's simple and easy to use, but quite serviceable.

I made a slight change to your script though (hope you don't mind). Instead of using five variables, it just adds progressively adds letters to one. This way it can handle any number of strokes, and it actually simplifies the code a bit (no more loops). I added a new six-stroke gesture, M, as an example.

Code:
;this script tracks up (u) down (d) left (l) and right (r). There is a tolerance of +/- 45 degrees, so it is quite simple and accurate
;gestures can have curves. eg a circle drawn from the top and clockwise is registered as rdlu (right down left up)
;if a gesture is down (d) and right (r), like an "L", a subroutine called gdr ( for gesture down right) will be called
;if anything is labelled as gdr:, the action will be run
;as a further example, if an "S" is drawn (from top to bottom), gldrdl: (gesture left down right down left) will be called
;these 2 examples are included, as is "M" (U R D U R D)

CoordMode, Mouse, Screen
rbutton::
mousegetpos,xpos1, ypos1
gesture=      ;clear previous tracking results, variable array gesture1 to gesture5
settimer, gesture, 10
return

rbutton up::
settimer, gesture, off
gesture := "g" . gesture   ;eg. gdr = gesture down right, gestures 3,4 and 5 did not occur
if islabel(gesture)<>0              ;checks if gesture is labelled
   gosub, %gesture%         ; eg. gosub, gdr
;msgbox,,, %gesture% not yet defined,4       ;delete this line once set up
return

gesture:
mousegetpos,xpos2, ypos2
dx:=xpos2-xpos1     
dy:=ypos1-ypos2     
if (abs(dy)>=abs(dx))   
   {
   if (dy>0)
      track=u  ;track is up
   else
      track=d     ;down   
   }
else
   {
   if (dx>0)
      track=r      ;right
   else
      track=l      ;left
   }
if (abs(dy)<4 and abs(dx)<4)
   track=         ;not tracking at all if no significant change in x or y
xpos1:=xpos2
ypos1:=ypos2
if (track<>SubStr(gesture, 0, 1))     ;ignore track if not changing since previous track
   gesture := gesture . track
return

g:          ;normal right click
click, right, xpos1, ypos1
exit

gdr:         ;delete examples when set up
msgbox, you drew an L
exit

gldrdl:
msgbox, you drew an S
exit

gurdurd:
msgbox, you drew an M
exit
Back to top
View user's profile Send private message
rodfell



Joined: 05 Oct 2007
Posts: 138
Location: Bundaberg (Bundy), Qld, Australia

PostPosted: Wed Nov 07, 2007 11:01 am    Post subject: substr Reply with quote

yeah i like that. i haven't got around to working out the substr function yet (still a bit of a noob). However, I would draw an M as (from bottom left) up down up down. As long as all angles are less than 45 degrees (fairly hard to make any greater than 45), the gesture for M would be gudud. N would be gudu. C would be gldr etc.
On my 24/7 ahk file, gu is maximize, gd is minimize, gl is back gr is forward.
Back to top
View user's profile Send private message
rodfell



Joined: 05 Oct 2007
Posts: 138
Location: Bundaberg (Bundy), Qld, Australia

PostPosted: Sun Nov 11, 2007 12:21 am    Post subject: added a few more examples and tweaks Reply with quote

added a few more examples and tweaks
Code:

;simple mouse gestures call subroutines based on a gesture (right button)
;the script tracks up (u) down (d) left (l) and right (r). There is a tolerance of +/- 45 degrees, so it is quite simple and accurate
;gestures can have curves. eg a circle drawn from the top and clockwise is registered as rdlu (right down left up)
;if a gesture is down (d) and right (r), like an "L", a subroutine called gdr ( for gesture down right) will be called
;if anything is labelled as gdr:, the action will be run
;as a further example, if an "S" is drawn (from top to bottom), gldrdl: (gesture left down right down left) will be called
;these 2 examples are included. See below for further examples

CoordMode, Mouse, Screen
winget, window0, id, ahk_class Progman   ;not needed to make a gesture, window0 is used in subroutines called by gestures used on the desktop. see gu: subroutine example

rbutton::
if (window1<>window0)      ;these 2 lines do not help the creation of gestures. The variable window2 can be used by subroutines called
   window2:=window1    ;by the gestures eg. maximize previous window
mousegetpos,xpos1, ypos1,window1   ;window1 can be used by subroutines eg maximize window under cursor
gesture=      ;clear previous tracking results, variable array gesture1 to gesture5
settimer, gesture, 10
return

rbutton up::
settimer, gesture, off
gesture := "g" . gesture   ;eg. gdr = gesture down right
if islabel(gesture)<>0              ;checks if gesture is labelled
   gosub, %gesture%         ; eg. gosub, gdr
msgbox,,, %gesture% not yet defined,4     
return

gesture:
mousegetpos,xpos2, ypos2
dx:=xpos2-xpos1     
dy:=ypos1-ypos2     
if (abs(dy)>=abs(dx))   
   {
   if (dy>0)
      track=u  ;track is up
   else
      track=d     ;down   
   }
else
   {
   if (dx>0)
      track=r      ;right
   else
      track=l      ;left
   }
if (abs(dy)<4 and abs(dx)<4)
   track=         ;not tracking at all if no significant change in x or y
xpos1:=xpos2
ypos1:=ypos2
if (track<>SubStr(gesture, 0, 1))     ;ignore track if not changing since previous track
   gesture := gesture . track
return

g:          ;normal right click
click, right, xpos1, ypos1
exit

;;;;;;; Examples ;;;;;;;;;;;;;;;;;;;;;;;;;;

gu:             ;; gesture up ;; maximize window under cursor. maximize last window if cursor over desktop
if (window1=window0)
   {
   if (window2<>"")
   winmaximize, ahk_id %window2%
   }
else
   winmaximize, ahk_id %window1%
exit

gd:            ;minimize window under cursor
if (window1<>window0)
   winminimize, ahk_id %window1%
exit

gl:            ;browser back
winactivate, ahk_id %window1%   
sendinput, {Browser_Back}
exit   

gr:            ;browser forward
winactivate, ahk_id %window1%   
sendinput, {Browser_Forward}
exit

gdr:            ;restore last window.
winrestore, ahk_id %window2%
exit

gldr:            ;close window under cursor (draw a C)
if (window1<>window0)
   winclose, ahk_id %window1%
exit

gldrdl:
msgbox, you drew an S
exit

gurdurd:
msgbox, you drew an M
exit

Back to top
View user's profile Send private message
MarkyMark



Joined: 28 Sep 2007
Posts: 26

PostPosted: Sat Jan 19, 2008 3:30 pm    Post subject: Reply with quote

Thanks rodfell for the script. Was looking for something lean and easy. Your works well.
Back to top
View user's profile Send private message
Marky
Guest





PostPosted: Tue Jan 22, 2008 2:45 pm    Post subject: Reply with quote

Is it possible to do a mouse gesture on a per application (ifwinactive) basis?
Back to top
ManaUser



Joined: 24 May 2007
Posts: 1121

PostPosted: Tue Jan 22, 2008 5:27 pm    Post subject: Reply with quote

You could just do this:
Code:
gldrdl:
IfWinActive ahk_class MozillaUIWindowClass
   msgbox, You drew an S, in Firefox!
Else IfWinActive ahk_class Notepad
   msgbox, You drew an S, in notepad!
Else
   msgbox, You drew an S, somewhere else!
exit

That's probably the best way actually.
Back to top
View user's profile Send private message
MarkyMark



Joined: 28 Sep 2007
Posts: 26

PostPosted: Tue Jan 22, 2008 10:31 pm    Post subject: Reply with quote

ManaUser

Thank you. I appreciate it. Smile
Back to top
View user's profile Send private message
lilljimpa



Joined: 18 Apr 2007
Posts: 127

PostPosted: Wed Jan 23, 2008 11:39 am    Post subject: Reply with quote

how do i add a weelup and weeldown to this gesture?

ex:

gweelup:
msgbox, you scroll up
exit
_________________
you'll have to excuse me...I'm from Sweden, so my English is not that good...(but now it's better cuz JSLover/Guest is helping me)...
Back to top
View user's profile Send private message Send e-mail MSN Messenger
ManaUser



Joined: 24 May 2007
Posts: 1121

PostPosted: Wed Jan 23, 2008 6:28 pm    Post subject: Reply with quote

lilljimpa wrote:
how do i add a weelup and weeldown to this gesture?

Heh, this is getting not-so-simple but here goes: (magenta parts are new)
Code:
;simple mouse gestures call subroutines based on a gesture (right button)
;the script tracks up (u) down (d) left (l) and right (r). There is a tolerance of +/- 45 degrees, so it is quite simple and accurate
;gestures can have curves. eg a circle drawn from the top and clockwise is registered as rdlu (right down left up)
;if a gesture is down (d) and right (r), like an "L", a subroutine called gdr ( for gesture down right) will be called
;if anything is labelled as gdr:, the action will be run
;as a further example, if an "S" is drawn (from top to bottom), gldrdl: (gesture left down right down left) will be called
;these 2 examples are included. See below for further examples

CoordMode, Mouse, Screen
winget, window0, id, ahk_class Progman   ;not needed to make a gesture, window0 is used in subroutines called by gestures used on the desktop. see gu: subroutine example

rbutton::
if (window1<>window0)      ;these 2 lines do not help the creation of gestures. The variable window2 can be used by subroutines called
   window2:=window1    ;by the gestures eg. maximize previous window
mousegetpos,xpos1, ypos1,window1   ;window1 can be used by subroutines eg maximize window under cursor
gesture=      ;clear previous tracking results, variable array gesture1 to gesture5
settimer, gesture, 10
GestureMode = 1
return

rbutton up::
settimer, gesture, off
GestureMode = 0
gesture := "g" . gesture   ;eg. gdr = gesture down right
if islabel(gesture)<>0              ;checks if gesture is labelled
   gosub, %gesture%         ; eg. gosub, gdr
msgbox,,, %gesture% not yet defined,4
return

gesture:
mousegetpos,xpos2, ypos2
dx:=xpos2-xpos1     
dy:=ypos1-ypos2     
if (abs(dy)>=abs(dx))   
   {
   if (dy>0)
      track=u  ;track is up
   else
      track=d     ;down   
   }
else
   {
   if (dx>0)
      track=r      ;right
   else
      track=l      ;left
   }
if (abs(dy)<4 and abs(dx)<4)
   track=         ;not tracking at all if no significant change in x or y
xpos1:=xpos2
ypos1:=ypos2
if (track<>SubStr(gesture, 0, 1))     ;ignore track if not changing since previous track
   gesture := gesture . track
return

WheelUp:: ;Since u and d are taken, we'll use + and - for the mouse wheel.
If GestureMode ;we're currently recording a gesture
{
   If (SubStr(gesture, 0) != "+") ;Don't record two wheelups in a row
      gesture := gesture . "+"
}
Else ;we're not recording a gesture so just do a wheelup
   Send {WheelUp}
Return

WheelDown:: ;ditto for down
If GestureMode
{
   If (SubStr(gesture, 0) != "-")
      gesture := gesture . "-"
}
Else
   Send {WheelDown}
Return


g:          ;normal right click
click, right, xpos1, ypos1
exit

;;;;;;; Examples ;;;;;;;;;;;;;;;;;;;;;;;;;;

gu:             ;; gesture up ;; maximize window under cursor. maximize last window if cursor over desktop
if (window1=window0)
   {
   if (window2<>"")
   winmaximize, ahk_id %window2%
   }
else
   winmaximize, ahk_id %window1%
exit

gd:            ;minimize window under cursor
if (window1<>window0)
   winminimize, ahk_id %window1%
exit

gl:            ;browser back
winactivate, ahk_id %window1%   
sendinput, {Browser_Back}
exit   

gr:            ;browser forward
winactivate, ahk_id %window1%   
sendinput, {Browser_Forward}
exit

gdr:            ;restore last window.
winrestore, ahk_id %window2%
exit

gldr:            ;close window under cursor (draw a C)
if (window1<>window0)
   winclose, ahk_id %window1%
exit

gldrdl:
msgbox, you drew an S
exit

gurdurd:
msgbox, you drew an M
exit

g+:
MsgBox WheelUp
exit

g-:
MsgBox WheelDown
exit

gl+:
MsgBox Left-WheelUp
exit
Back to top
View user's profile Send private message
rodfell



Joined: 05 Oct 2007
Posts: 138
Location: Bundaberg (Bundy), Qld, Australia

PostPosted: Sat Jan 26, 2008 4:13 am    Post subject: wheel up down Reply with quote

why do you need wheelup and wheel down? I tried for simplicity. If there's a good reason for it, i'll try to incorporate it.
Back to top
View user's profile Send private message
lilljimpa



Joined: 18 Apr 2007
Posts: 127

PostPosted: Sat Jan 26, 2008 3:15 pm    Post subject: Re: wheel up down Reply with quote

rodfell wrote:
why do you need wheelup and wheel down? I tried for simplicity. If there's a good reason for it, i'll try to incorporate it.


i have my reason Wink i have add a trancparent to the gesture, not as good i hope for but it's working nice
_________________
you'll have to excuse me...I'm from Sweden, so my English is not that good...(but now it's better cuz JSLover/Guest is helping me)...
Back to top
View user's profile Send private message Send e-mail MSN Messenger
rodfell



Joined: 05 Oct 2007
Posts: 138
Location: Bundaberg (Bundy), Qld, Australia

PostPosted: Sun Jan 27, 2008 3:44 am    Post subject: Reply with quote

i get it now. i can see when the wheelup and down would be useful eg volume up and down. I played around with other ways of doing what you wanted but no success. the trouble is getkeystate doesn't work with wheelup and wheeldown. i have incorporated your code into my 24/7 ahk file
Back to top
View user's profile Send private message
Icarus



Joined: 24 Nov 2005
Posts: 851

PostPosted: Sun Jan 27, 2008 2:43 pm    Post subject: Reply with quote

A very nice and smart script.

I noticed there is one problem when gesturing diagonals - the script continuously records "dldldldldl".

I would also suggest to include diagonal as a valid gesture - this will allow to have things not possible now - for example, an "R" shaped gesture is not logged correctly now, since the leg of the R is sometimes recorded as R and sometimes as D (and sometimes as both).

I may try to do the change, if I do, I will post here.
Back to top
View user's profile Send private message Visit poster's website
ManaUser



Joined: 24 May 2007
Posts: 1121

PostPosted: Sun Jan 27, 2008 6:18 pm    Post subject: Reply with quote

I think some of you are missing the point. ^_^ This was supposed to be simple, simple.

There are other more complex/advanced gestures scripts already.


Last edited by ManaUser on Tue Jan 29, 2008 11:27 pm; edited 1 time in total
Back to top
View user's profile Send private message
Display posts from previous:   
Reply to topic    AutoHotkey Community Forum Index -> Scripts & Functions All times are GMT
Goto page 1, 2, 3, 4, 5, 6, 7, 8  Next
Page 1 of 8

 
Jump to:  
You can post new topics in this forum
You can reply to topics in this forum


Powered by phpBB © 2001, 2005 phpBB Group