/*
REMAPPING TOUCHES POUR ACTIVEGS + Extras
(script AutoHotkey)
v0.92 (13.01.2013)
Auteur : Arnaud C. (pour WWW.CTRL-POMME-RESET.FR)

Testé avec : 
AUTOHOTKEY v1.1.09.02
WINDOWS XP SP3
Clavier AZERTY Logitech G11
ActiveGS v3.5.903 beta

notes (codes AutoHotkey):
+ : SHIFT
^ : CTRL
! : ALT
<^>! : ALTR Gr
# : Win
SC : Scan Code
VK : Virtual Key


Fonctionnalités du script :
===========================
- remapping des touches clavier AZERTY avec ActiveGS (plugin et standalone Windows) et GSPort.
- support du multi-sessions d'ActiveGS standalone Windows pour les fonctionnalités suivantes :
- ouverture automatique au lancement de la fenêtre des Options d'ActiveGS standalone (version Windows).
- mode "magnétique" pour la fenêtre des Options (ActiveGS standalone Windows).
- déplacement de la fenêtre des Option autour de la fenêtre principale par CTRL+HOME (ActiveGS standalone Windows).
- suppression ponctuelle par CTRL+END du logo d'accès disque lorsque ActiveGS standalone Windows est en pause (cela permet la prise de screenshot sans élement disgracieux).
- ajout lors de la mise en pause d'ActiveGS standalone Windows d'un message dans la barre de titre de la fenêtre en question pour signaler l'état.

Hotkeys ajoutées :
==================
- touche "Right Windows" (clavier PC) qui peut faire office de ALT Gr (si problème pour obtenir certains caractères sous GS/OS et CDA).
- CTRL+SHIFT+ESC = fermeture du script.
- F12 = fonction COLLER clipboard vers ActiveGS (pendant le processus, ESC permet de le terminer et ESPACE le met en pause).
- Insert = ouverture de GS/BUG (si installé).

Problèmes et/ou limitations connus :
====================================
- exécution d'un seul processus de COLLER à la fois même en cas de multi-sessions d'ActiveGS.
- lors du processus de COLLER, changer de fenêtre et revenir sur la fenêtre ActiveGS entraîne la perte d'un (ou deux) caractère(s).
       solution : => utiliser la fonction PAUSE avant de changer de fenêtre.


Historique :
============
- 0.92		: fonction COLLER : a) ajout d'une fonction PAUSE (Espace) pendant le processus avec ouverture d'une MsgBox. 
                                b) plus de tempo pour les textes courts (<257 car.)
- 0.91		: amélioration de la fonction COLLER.
- 0.90	(*)	: première version avec gestion du "coller VERS ActiveGS" depuis le presse-papier (texte).

- 0.80		: première version avec gestion multi-sessions d'ActiveGS.

- 0.56		: HotKey (INS) pour activer GS/BUG facilement enfin totalement opérationnelle !
- 0.55		: RightWin = touche alternative à ALT Gr (qui pose des problèmes de reconnaissance sous GS/OS et avec certains CDA).
- 0.54	(*)	: HotKey "Insert" pour activer facilement GS/BUG (beta).
- 0.53		: prise en compte de la modification "underscore" (voir www.ctrl-pomme-reset.fr) de ActiveGS standalone PC.
- 0.52	(*)	: ajout Hotkey (F7) pour activer facilement GS/BUG (alpha) -> touche INS à partir de 0.54+.
- 0.51	(*)	: corrections bugs divers.
- 0.50		: ajout Hotkey pour cacher/afficher le symbole d'accès disque quand l'émulateur est en pause par F5.
			: ajout texte (paused) dans la barre de titre pour la version standalone d'ActiveGS si l'émulateur en pause par F5.
- 0.49	(*)	: amélioration de l'ouverture automatique de la fenêtre options.
- 0.48		: ajout du remapping avec le plugin IE et Firefox pour les sites FTA et Virtual Apple uniquement.
- 0.47	(*)	: fenêtre options "magnétique" déplaçable par ctrl+Tab (version standalone ActiveGS uniquement) -> CTRL+HOME à partir de 0.5x.
- 0.46	(*)	: fenêtre options type "magnétique" + Plugin Chrome correctement remappé (sans interférences avec les autres onglets).
- 0.45	(*)	: amélioration du déplacement de la fenêtre options après ouverture + correction de petits bugs.
- 0.44 	(*)	: ajout (alpha) du support d'ActiveGS version Plugin (Chrome/IE/Firefox) et de GSport.
- 0.43 		: limitation de l'utilisation du Numpad.
- 0.42 		: première version "stable" diffusée.
- 0.xx	(*)	: versions alpha de développement.

(*) : version de travail, non released

*/ 
; ===========================================================================
; PART 0 : déclaration variables et paramètres pour le script

#SingleInstance force ; une seule version de ce script active en même temps
#Persistent ; maintient le script running

TitlePause = (** paused **) ; apparence titre fenêtre si en pause par F5

SetTitleMatchMode 1 ; mode de détection du texte des fenêtres

GroupAdd, ActiveGS_Group, ActiveGS ahk_class AfxFrameOrView90s 		; ajout de ActiveGS Standalone Windows
GroupAdd, ActiveGS_Group, %TitlePause% ahk_class AfxFrameOrView90s 	; + version "paused"

GroupAdd, ActiveGS_Group, ahk_class gsport							; ajout de GSport (v0.2a)

GroupAdd, ActiveGS_Group, ahk_class Chrome_WidgetWin_1, activegs	; ajout de ActiveGS Plugin Chrome  (Chrome OK)

; pour IE et Firefox, ajout par "sites"
GroupAdd, ActiveGS_Group, Apple`, 2GS`, GS`, Emulator				; ajout du site http://www.freetoolsassociation.com/
GroupAdd, ActiveGS_Group, Virtual Apple								; ajout du site http://www.virtualapple.org/
; 

GroupAdd, Standalone_Group, ActiveGS ahk_class AfxFrameOrView90s	 ; ajout version standalone + paused only
GroupAdd, Standalone_Group, %TitlePause% ahk_class AfxFrameOrView90s ; pour déplacement options + show/hide voyant

nbWindows =0 		; aucune fenêtre pour le moment
counterWindows =1	; 

; PART I : OUVERTURE + DEPLACEMENT FENETRE OPTIONS d'ACTIVEGS

SetTimer, CheckActiveGS, 100 ; set timer 100ms
return

CheckActiveGS:

WinGet, winarray, list, ahk_group Standalone_Group ; // on récupère le nombre de fenêtres d'ActiveGS ouvertes

if (winarray = 0)  ; remise à zero si plus de fenêtre
	{
	nbWindows := 0
	counterWindows :=1
	return
	}

else if (winarray > nbWindows) ; si nouvelle fenêtre ActiveGS détectée
	{
	OpenDialogBox() ; on ouvre la boite de dialogue
	return
	}

else if (winarray < nbWindows)
	{
	nbWindows := winarray
	}

GetKeyState, state, LBUTTON

if state = D
	{
	tempID := WinExist("A")
	tempInd := GetIndex(tempID) 
	if  (tempInd <> 0)
		{
		WinGetPos, X_ActiveGS,Y_ActiveGS,Width_ActiveGS,Height_ActiveGS, ahk_id %tempID%
		if (X_ActiveGS !=X_Old%tempInd% || Y_ActiveGS !=Y_Old%tempInd% || Height_ActiveGS !=H_Old%tempInd% || Width_ActiveGS != W_Old%tempInd%)
			{
			MoveDialogBox(tempInd)
			}
		
		}
	}
	
return

; ==========================================================================================================
OpenDialogBox()
{
global

local xclick, yclick, tempid, temppid

WinActivate, ahk_group Standalone_Group ; on active la fenêtre principale ActiveGS

varid%counterWindows% := WinExist("A") 	; on récupère l'ID de la fenêtre active

tempid :=varid%counterWindows%

Winget, varpid%counterWindows%, PID, ahk_id %tempid% ; on récupère le Process ID de la fenêtre courante

temppid := varpid%counterWindows%

WinGetPos, X_Old%counterWindows%,Y_Old%counterWindows%,W_Old%counterWindows%,H_Old%counterWindows%, ahk_id %tempid% ; on détecte la première position 

WinGetTitle, ActiveText%counterWindows%, ahk_id %tempid% ; on en profite pour récupérer le titre de la fenêtre

WinActivate, ahk_id %tempid% ; on active la fenêtre principale
xclick :=W_Old%counterWindows%/2
yclick :=H_Old%counterWindows%/2
Click right %xclick%,%yclick% ; on simule clic droit

WinActivate, ahk_id %tempid% ; on réactive la fenêtre principale

Pos_options%counterWindows% := 1 ; position 1 par défaut
bHide%counterWindows% :=0 ; icon disk non caché par défaut
bPaused%counterWindows% :=0 ; non en pause par défaut


IfWinNotExist, ahk_pid %temppid% ahk_class #32770 ; est-ce que la boite de dialogue option est déjà ouverte ?
	{ ; si non :
	return
	}

nbWindows := winarray 	; on récupère le nb d'ActiveGS ouvert	

MoveDialogBox(counterWindows) ; on déplace la dialogBox
	
counterWindows := ++counterWindows 	; on incrémente le nb d'ActiveGS max pour l'éventuel prochaine session
return
}

MoveDialogBox(countWindows)
{
global

local temppid, w_options, h_options,X, Y

temppid :=varpid%countWindows%

WinGetPos, X_Old%countWindows%,Y_Old%countWindows%,W_Old%countWindows%,H_Old%countWindows%, ahk_pid %temppid% ahk_class AfxFrameOrView90s 

WinGetPos,,,w_options,h_options, ahk_pid %temppid% ahk_class #32770 ; récupère dimension boite dialogue
	if (Pos_options%countWindows% =0)
		{
		X := X_Old%countWindows% + W_Old%countWindows% -1
		Y := Y_Old%countWindows% + (H_Old%countWindows%-h_options)/2
		}
	else if (Pos_options%countWindows% =1)
		{
		X := X_Old%countWindows% + (W_Old%countWindows%-w_options)/2
		Y := Y_Old%countWindows% + H_Old%countWindows% -1
		}
	else if (Pos_options%countWindows% =2)
		{
		X := X_Old%countWindows% - w_options + 1
		Y := Y_Old%countWindows% + (H_Old%countWindows%-h_options)/2
		}
	else if (Pos_options%countWindows% =3)
		{
		X := X_Old%countWindows% + (W_Old%countWindows%-w_options)/2
		Y := Y_Old%countWindows% - h_options + 2
		}
	
WinMove, ahk_pid %temppid% ahk_class #32770,, X,Y ; on déplace la fenêtre en X,Y

return
}

GetIndex(tempid)
{
global

Loop, %counterWindows%
	{
	if (varid%A_Index% = tempid)
		{
		return A_Index
		}
	}
return 0 
}

; ==========================================================================================================

; PART II : Hotkeys du Script

^+Esc:: ExitApp ; CTRL+SHIFT+ESC = fin du script
return

^Home:: ; CTRL+HOME = déplacement fenêtre options "magnétique" autour de la fenêtre d'ActiveGS
temp1 := WinExist("A") ; on récupère l'ID de la fenêtre active
temp2 := GetIndex(temp1) ; on calcule l'index associé

; calcul nouvelle position boite de dialogue
Pos_options%temp2% := ++Pos_options%temp2% ; sens aiguilles d'une montre...
if Pos_options%temp2% = 4 
Pos_options%temp2% =0

MoveDialogBox(temp2) ; et déplacement/affichage
return

^End:: ; CTRL+END = cache/affiche le logo d'accès disque quand l'émulateur est en pause par F5
temp1 := WinExist("A") ; on récupère l'ID de la fenêtre active
temp2 := GetIndex(temp1) ; on calcule l'index associé

if (bHide%temp2% = 0)
{
Control, Hide,,#327702,ahk_id %temp1%
bHide%temp2% = 1
}
else
{
Control, Show,,#327702,ahk_id %temp1%
bHide%temp2% = 0
}
return

/* 
Pause::   ; fonction pause alternative (désactivée par defaut)
SendMessage, 0x1330, 1,, SysTabControl321, ahk_class #32770 ; ; active Onglet "Runtine Info"
ControlClick, Button1,,Pause/Resume,LEFT ; clic bouton Pause/Resume
return
*/

; PART III : REMAPPING DES TOUCHES

#IfWinActive ahk_group Standalone_Group ; pour ActiveGS standalone (en pause ou pas) actif uniquement !

; ne pas modifier - ne concerne pas le mapping des touches !
F5:: ; interception touche F5 "Pause" pour fonction Hide/Show symbole accès disque + title fenêtre
temp1 := WinExist("A") ; on récupère l'ID de la fenêtre active
temp2 := GetIndex(temp1) ; on calcule l'index associé
bHide%temp2% = 0 ; mode show par défaut
if (bPaused%temp2% = 0) ; pas en pause
{
WinSetTitle, ahk_id %temp1% ahk_class AfxFrameOrView90s,, %TitlePause%
bPaused%temp2% = 1 ; pause boléan
}
else ; si on est en pause
{
Affichetitle := ActiveText%temp2%
WinSetTitle, ahk_id %temp1% ahk_class AfxFrameOrView90s,, %AfficheTitle%
bPaused%temp2% = 0
}
SendInput {F5} ; pause/resume
return
; fin de non modification


#IfWinActive ahk_group ActiveGS_Group ; pour ActiveGS (standalone et plugin) et GSport actif uniquement !

; touches "haut du clavier"

+&::SendInput &				; 1
&::SendInput +è				; &

RWIN & é::SendInput +ù		; ~ (bis)
<^>!é::SendInput +ù			; ~
+é::SendInput é				; 2
é::SendInput +)	  			; é

RWIN & "::SendInput +{VK33}	; # (bis)
<^>!"::SendInput +{VK33}	; #
+"::SendInput {VK33} 		; 3
"::SendInput +²  			; "

RWIN & '::SendInput +)		; { (bis)
<^>!'::SendInput +)			; {
+'::SendInput '				; 4
'::SendInput ²				; '

RWIN & (::SendInput )		; [ (bis)
<^>!(::SendInput )			; [
+(::SendInput (				; 5
(::SendInput +ç 			; (

RWIN & -::SendInput +µ		; | (bis)
<^>!-::SendInput +µ			; |
+-::SendInput -				; 6
-::SendInput {NumpadSub}	; -

RWIN & è::SendInput {VKC0}	; ` (bis)
<^>!è::SendInput {VKC0}		; `
+è::SendInput è				; 7
è::SendInput +¨ 			; è 

RWin & _::SendInput *		; \ (bis)
<^>!_::SendInput *			; \
+_::SendInput _				; 8 (si modification "underscore")
_::SendInput +_				; _ (si modification "underscore")

RWIN & ç::SendInput +-		; ^ (bis)
<^>!ç::SendInput +-			; ^
+ç::SendInput ç			 	; 9
ç::SendInput *				; ç 

RWIN & à::SendInput +é		; @ (bis)
<^>!à::SendInput +é			; @
+à::SendInput à			 	; 0
à::SendInput +é				; à 

RWIN & )::SendInput {VKDD} 	; ] (bis)
<^>!)::SendInput {VKDD} 	; ]
+)::SendInput )				; ° 
)::SendInput +à				; )

RWIN & =::SendInput +¨		; } (bis)
<^>!=::SendInput +¨			; }

; autres touches 

+<::SendInput +;			; >
<::SendInput +?				; <

+,::SendInput +:			; ?

; +VKDD::SendInput +-		; ¨ (tréma non géré ?)
VKDD::SendInput +-			; ^ (accent circonflexe)

+$::SendInput +"			; £
$::SendInput +'				; $

*::SendInput {NumpadMult}	; *


+ù::SendInput +(			; %
ù::SendInput +*				; ù

+VKBE::SendInput {VKBE}		; .
VKBE::SendInput $			; ;

+VKBF::SendInput {VKBF}		; /
:::SendInput +$				; :

+!::SendInput {VKDD}		; §
!::SendInput +&				; !

; divers

Ins::						; GS/BUG CTRL+OPEN-APPLE+OPTION+ESC (CTRL+ALT+WIN+ESC sur PC)
 SendInput {LALT down}{LCTRL down}{LWIN down}{ESC down}{ESC up}{LWIN up}{LCTRL up}{LALT up}
return

; ===========================================================================================
F12::						; PASTE CLIPBOARD vers ACTIVEGS

ident := WinExist("A") ; on récupère l'ID de la fenêtre ActiveGS active
index = 1
StringSplit, data, clipboard
length := data0 ; longueur
if (length>256)
	SetKeyDelay,35				; délai d'attente (ms) !
	
while (index<=length)
{
 ifWinActive,ahk_id %ident%
 {
	if (GetKeyState("Esc","P") = 1)
		break

	if (GetKeyState("space","P") = 1)
		{
		Send {space} 		; astuce pour éviter le bug de l'espace "fou"
		Send {backspace}	; 
		MsgBox, 52, L'opération COLLER est en pause,Voulez-vous poursuivre ?
		ifMsgBox, No	; si non on stoppe la boucle et on sort
			break 
		ifMsgBox, Yes	; si oui on réactive la fenêtre ActiveGS et on continue le process
			{
			WinActivate, ahk_id %ident%
			} 
		}
	
	if (data%index% = "1")
	{
	Send &	
	}
	else if (data%index% = "2") 
	{
	Send é
	}
	else if (data%index% = "3") 
	{
	Send {VK33}
	}
	else if (data%index% = "4") 
	{
	Send '
	}
	else if (data%index% = "5") 
	{
	Send (
	}
	else if (data%index% = "6") 
	{
	Send -
	}
	else if (data%index% = "7") 
	{
	Send è
	}
	else if (data%index% = "8") 
	{
	Send _
	}
	else if (data%index% = "9") 
	{
	Send ç
	}
	else if (data%index% = "0") 
	{
	Send à
	}
	else if (data%index% = "(") 
	{
	Send +ç
	}
	else if (data%index% = ")") 
	{
	Send +à
	}
	else if (data%index% = "^") 
	{
	Send +-
	}
	else if (data%index% = "-") 
	{
	Send {NumpadSub}
	}
	else if (data%index% = "+") 
	{
	Send {NumpadAdd}
	}
	else if (data%index% = "*") 
	{
	Send {NumpadMult}
	}
	else if (data%index% = "/") 
	{
	Send {VKBF}
	}
	else if (data%index% = ".") 
	{
	Send {VKBE}
	}
	else if (data%index% = ";") 
	{
	Send $
	}
	else if (data%index% = "%") ; %
	{
	Send +(
	}
	else if (data%index% = ":") 
	{
	Send +$
	}
	else if (data%index% = "!") 
	{
	Send +&
	}
	else if (data%index% = "$") 
	{
	Send +'
	}
	else if (asc(data%index%) = 34) ; "
	{
	Send +²
	}
	else if (data%index% = "[") 
	{
	Send )
	}
	else if (data%index% = "]") 
	{
	Send {VKDD} 
	}
	else if (data%index% = "&") 
	{
	Send +è
	}
	else if (data%index% = "?") 
	{
	Send +:
	}
	else if (data%index% = ">") 
	{
	Send +;
	}
	else if (data%index% = "<") 
	{
	Send +?
	}
	else if (data%index% = "{") 
	{
	Send +)
	}
	else if (data%index% = "}") 
	{
	Send +¨
	}
	else if (data%index% = "#") 
	{
	Send +{VK33}
	}
	else if (data%index% = "'") 
	{
	Send ²
	}
	else if (data%index% = "|") 
	{
	Send +µ
	}
	else if (data%index% = "@") 
	{
	Send +é
	}
	else if (data%index% = "é") 
	{
	Send +)
	}
	else if (data%index% = "è") 
	{
	Send +¨
	}
	else if (data%index% = "ç") 
	{
	Send *
	}
	else if (data%index% = "à") 
	{
	Send +é
	}
	else if (data%index% = "ù") 
	{
	Send +*
	}
	else if (data%index% = "°") 
	{
	Send )
	}
	else if (data%index% = "§") 
	{
	Send {VKDD}
	}
	else if (data%index% = "£") 
	{
	Send +"
	}
	else if (data%index% = "_") 
	{
	Send +_
	}
	else if (asc(data%index%) = 0x0D) 
	{
	Send {return}
	}
	else if (asc(data%index%) = 0x0A) 
	{
	; on ne fait rien (shunte 0x0A)
	}
	else 
	Send % data%index% 	; % (ne pas tenir compte du commentaire !) 
    
	index++
 }
}
SetKeyDelay, -1 ; retour à la normale
return