Menú

Mostrar Mensajes

Esta sección te permite ver todos los mensajes escritos por este usuario. Ten en cuenta que sólo puedes ver los mensajes escritos en zonas a las que tienes acceso en este momento.

Mostrar Mensajes Menú

Mensajes - Serapis

#101
Si, cuando falta contexto no se puede aportar más que lo específicamente solicitado.

Aún así, recuerda que el formulario tambien posee el evento keypress (no solo el textbox, aunque es el prototipo de control cuando se habla de texto).
Citar
por eso necesito saber cuanto tiempo permanece pulsada cada tecla para poder darle el tiempo a la luz encendida..
La duración de cada tecla, como te decía al comienzo, viene definida en las propiedades del teclado. Puedes cambiarlo si los valores no se adecúan a tus necesidades aunque sea provisionalmente: 'Repeat Delay' y en 'Repeat Rate'.
La lástima es que en la interfaz son sendos 'sliders' pero sin mostrar valores numéricos. Así que hay que tirar de código para obtenerlos...


De todos modos El retraso de repetición es elegible entre 0 y 3 segundos 0-3, sin intervalos intermedios entre segundos.
Y la cadencia de repetición es elegible entre: 0-31, aunque experimentalmente si pongo 0, observo que se repiten 2 caracteres por segundo.
Estos valores podrían estar alterados o ignorados si hay establecidas opciones de accesibilidad (Filterkeys). No lo he investigado, ya que nunca lo he necesitado ni personal ni profesionalmente.

Código (vb) [Seleccionar]

Const GETKEYBOARD_RATE      As Long = 10
Const GETKEYBOARD_DELAY     As Long = 22

Private Declare Function KeyboardRepeat Lib "user32" Alias "SystemParametersInfoA" (ByVal Accion As Long, ByVal Param1 As Long, Param2 As Any, ByVal Param3 As Long) As Long

Private Sub Form_Load()
    Dim kbState As Long
   
    Call KeyboardRepeat(GETKEYBOARD_DELAY, 0, kbState, 0)
    Debug.Print "Retraso de repeticion del teclado: " & kbState & " Sg." 
   
    Call KeyboardRepeat(GETKEYBOARD_RATE, 0, kbState, 0)
    Debug.Print "Cadencia de repeticion del teclado: " & kbState & " Caracteres por segundo"
End Sub


Tal como lo explicas, es un trabajo de chinos, pero en el vídeo se ve que te ha quedado bien...
#102
Tu necesidad está contenida en mi respuesta.

Por un lado, si tienes dos (o más) diccionarios a aplicar, puede suceder dos cosas:
- Que prepares los ficheros antes de abordar el ataque.
 En este caso, la respuesta la tienes en la parte superior de mi mensaje: Reunir un solo fichero el contenido de ambos sin repeticiones.
- Que abordes el ataque primero con un diccionario y luego debas preparar el segundo.
 en este caso, la respuesta la tienes en la parte inferior de mi mensaje (solo que má s simple, al no requerir guarda cada fichero si no solo el de tu interés): Reunir en un fichero las entradas que constan en el 2º que no contan en el primero.
Citarfuncion DiferenciaFiles(  RutaA, RutaB)
   abrir ficheros A1(rutaA), B1(rutaB)
   crear y abrir ficheros temporales A2, B2, C

   THash = llenar desde fichero A1
   Por cada linea1 en fichero B1
       h = Hashing(linea1)
       si tHash.Contiene(h)
            copiar linea1 al fichero C y THash.Eliminar(h)
       si no
            copiar linea1 al fichero B2
       fin si
   siguiente
   // como se han ido eliminando las entradas que están contenidas también en B1,
   // al final solo quedan entradas únicas en la tabla hash.
   por cada item en THash
       copiar item al fichero A2
   siguiente

   cerrar y eliminar A1, B1
   renombrar A2 como A1, y B2 como B1.

   cerrar ficheros

Adicionalmente, para futuras situaciones lo preferible es que cada diccionario contenga solo entradas únicas. Puedes realizar cualquiera de las soluciones que te propuse, pues la diferencia entre ambos casos es la cantidad de ficheros resultantes (pero en ambos casos cda fichero pasa a tener entradas únicas sin repeticiónes)

- La solución de la parte superior:  reúne en un solo fichero con las entradas que constan en ambos ficheros, pero sin repetidos.

- La solución de la parte inferior: te proporciona 3 ficheros distintos a partir de los 2 de entrada, los 3 tienen entradas unicas... (uno pasa a conteneder las entradas que solo constan en el él y no en el segundo, el otro pasa a tener igualmente las que solo constan en el y no en el primero, y un tercero pasa a contener las entradas que aparecían en ambos pero sin repetirse). Luego, puedes unirlos de la forma que te parezca o dejarlos sueltos.

En cualquiera de los casos dejan de existir entradas repetidas.



Cita de: EdePC en 11 Noviembre 2021, 22:33 PM
Con PowerShell se puede hacer fácilmente, darle x cantidad de wordlists, que ordene y quite duplicados para que luego se guarde en un nuevo wordlist limpio
mmmm... eso de fácilmente, lo tenemos que dejar aparte, si resulta ser verdad cuando dice:
Citar...con miles de millones de palabras
Ordenar miles de millones, requiere su tiempito y me temo que tampoco tendría suficiente RAM...
Un sencillo cálculo:
Imaginemos 4.000 millones (4 es un número pequeño en cuanto a 'miles'), suponiendo solo 10 caracteres por contraseña, ...tendríamos que, mantener en memoria el array supondría unos 37Gb. de RAM (UTF8)... ya ni contamos el tiempo de carga dle fichero al array.

Un problema así no puede abordarse con RAM si no tirando de ficheros... si hay que ordenar manteniendo en fichero, entonces resulta aún más eterno (cada entrada debe ser comparada una enorme cantidad de veces, tanto más cuanto mayor sea el array). Incluso la cantidad de veces que debe escribirse es log2(4.000 millones) más o menos 32 veces (2^32 =aprox. 4 mil 300 millones).

En cambio el uso de tablas hash, tirando de ficheros, no supone una sobrecarga excesiva, porque cada entrada se escribe una sola vez y se lee (de origen una vez +) en cálculo 1 vez + la cantidad de posibles colisiones que tuviere... (pongamos que cada entrada tuviere 10-50 colisiones de media), claro que la cantidad de colisiones de promedio dependerá del algoritmo de hashing utilizado. Pero salvo un muy mal algoritmo, esto sería rápido.

Una cosa es que el código sea 'fácil' de escribir y otra muy distinta que sea rentable ejecutarlo.
...claro que al final comenta sobre diccionarios de 1 millón de entradas (que es muy asumible), nada se sabe si solo es por ejemplificar o si es más o menos el caso real y arriba se coló poniendo 'miles de millones'.

Por descontado tener diccionarios de miles de millones de entrada, es monstruosamente estúpido. Las claves deberían ser generadas automáticamente a medida que se usan... usar y consumir.
#103
Programación Visual Basic / Re: eliminar registro
10 Noviembre 2021, 23:23 PM
En realidad, lo peor no es que no se borren los datos de los textbox (que no solo no importa si no que interesa conservarlo temporalmente)... lo peor es que no se borran de tu array.

Hay una variedad de indicaciones que dar y corregir... pero no quiero extenderme en explicaciones... porque son elementales y uno debiera ceñirse a ellos.

Te pòngo un código que puedes remplazar por todo lo que tienes. nota que he renombrado los textbox y los botones a un valor más acorde y el boton 'nuevo', en realidad sobra, aún así su código todavía es válido.

Nota también, que si no tienes más módulos de código donde uses esos registros de la agenda, el código en el módulo puede ser pasado al formulario (pero con alcance privado).

Código (vb) [Seleccionar]


Private Type Registro
    Nombre                  As String * 15
    Apellidos               As String * 25
    Telefono                As String * 15
    Edad                    As String * 3
End Type

Private Agenda(0 To 49)     As Registro
Private totalregistros      As Integer
Private NoUpdateTxts        As Boolean


Private Sub BtnAñadir_Click()
    If (totalregistros = 50) Then
        MsgBox "lista completa", 16, "error"
    Else
        If (Esregistrable = True) Then
            With Agenda(totalregistros)
                .Nombre = TxtNombre.Text
                .Apellidos = TxtApellidos.Text
                .Telefono = TxtTelefono.Text
                .Edad = Val(TxtEdad.Text)
            End With
           
            Combo2.AddItem TxtNombre.Text
            totalregistros = (totalregistros + 1)
           
            Call BtnNuevo_Click
        Else
            MsgBox "El registor está incompleto, no puede añadirse hasta que esté completo."
        End If
    End If
End Sub

Private Sub BtnEliminar_Click()
    Dim b As VbMsgBoxResult
    Dim index As Integer, k As Integer, j As Integer
   
    j = (Combo2.ListCount - 1)
    index = Combo2.ListIndex
    If (index = -1) Then  ' exit sub
        Combo2.ListIndex = j  ' si no hay ninguno seleccionado se supone el último.
        index = j
    End If
   
    b = MsgBox("Eliminar Registro: " + TxtNombre.Text, 3 + 32, "Eliminar")
    If (b = vbYes) Then
        ' Los datos a eliminar, se pasan a los textbox, por si se quiere volver a añadir o editar antes de añadir.
        Call Combo2_Click
        ' opcionalmente se puede simplemente borrar...
        'Call BtnNuevo_Click
       
        ' Eliminar el item del combo.
        Combo2.RemoveItem (index)
       
        ' Bajar todos los items en el array por encima del item eliminado una posición.
        For k = index To j - 1
            Agenda(k) = Agenda(k + 1)
        Next
       
        ' ahora el último ítem queda libre, se puede vaciar o dejarlo...
        With Agenda(k)
            .Nombre = ""
            .Apellidos = ""
            .Telefono = ""
            .Edad = ""
        End With
       
        ' queremos que en el combo siempre se vea un item.
        NoUpdateTxts = True
        If (j > 0) Then
            If (index < j) Then
                Combo2.ListIndex = index
            Else
                Combo2.ListIndex = (j - 1)
            End If
        End If
        NoUpdateTxts = False
       
        totalregistros = j ' descontar 1.
       
        ' Desactivar el botón eliminar si no quedan registros.
        BtnEliminar.Enabled = (totalregistros > 0)
    End If
End Sub

Private Sub BtnTerminar_Click()
    End
End Sub

Private Sub BtnNuevo_Click()
    TxtNombre.Text = ""
    TxtApellidos.Text = ""
    TxtTelefono.Text = ""
    TxtEdad.Text = ""
    TxtNombre.SetFocus
End Sub

Private Sub Combo2_Click()
    If (NoUpdateTxts = False) Then
        With Agenda(Combo2.ListIndex)
            TxtNombre.Text = .Nombre
            TxtApellidos.Text = .Apellidos
            TxtTelefono.Text = .Telefono
            TxtEdad.Text = Val(.Edad)
        End With
    End If
End Sub

Private Sub TxtEdad_GotFocus()
    Call SelOnGotFocus(TxtEdad)
End Sub

Private Sub TxtApellidos_GotFocus()
    Call SelOnGotFocus(TxtApellidos)
End Sub

Private Sub TxtNombre_GotFocus()
    Call SelOnGotFocus(TxtNombre)
End Sub

Private Sub TxtTelefono_GotFocus()
    Call SelOnGotFocus(TxtTelefono)
End Sub

Private Sub SelOnGotFocus(ByRef Txt As TextBox)
    Txt.SelStart = 0
    Txt.SelLength = Len(Txt.Text)
End Sub

' Verifica que los campos dle registor no quedan vacíos (sdon obligatorios)
'  Si un campo no es obligatorio, debe retirarse de aquí.
Private Function Esregistrable() As Boolean
    If (Len(Me.TxtNombre.Text) > 0) Then
        If (Len(Me.TxtApellidos.Text) > 0) Then
            If (Len(Me.TxtTelefono.Text) > 0) Then
                Esregistrable = IsNumeric(Me.TxtEdad.Text)
            End If
        End If
    End If
End Function

'Private Sub Form_Load()
'    totalregistros = 0
'End Sub


Ejecuta el código paso a paso al menos el del botón eliminar, para ver qué va sucediendo a cada instante... (arranca la aplicación con la tecla F8, o bien pon un punto de interrupción (tecla F9) en la línea del boton eliminar y cuando llegue allí se parará y entonces ejecuta paso a paso con la tecla F8).


Por favor, como ya llevas tiempo en el foro, acostumbra a colocar tu código entre etiquetas GESHI (elige VB), que aparecen en el editor cuando redactas tu mensaje...
#104
adla,  Tengo una buena noticia para tí...

Me picaba el gusanillo de probar que de alguna manera fuera posible y simple lograr lo que reclamas y lo he conseguido.
Que conste que no hay funcionalidad documentada al respecto, a sí que ha sido tirar de intuición y pruebas.

VB6 suele pasar sus parámetros por referencia... en general esto es más rápido que copiar el valor a una nueva variable y es una razón de peso (velocidad), por la que muchos lenguajes por defecto, han pasado (y siguen pasando) parámetros por referencia...
No obstante esto mismo permite modificar el valor en origen, por lo que ha sido cuestión de probar ciertos casos para jugar con tal eventualidad.

Con el evento keydown, el problema es que te pasa el 'keycode' que es la tecla pulsada, esto es muy útil, ya que te salta cuando pulsas la 'A' pero también cuand pulsas las teclas de cursor, muy útil si tratas de controlar por ejemplo el reposicionamiento del cursor en un control diseñado por tí.
Tu caso es no permitir repetición de teclas pero solo en el caso de las teclas imprimibles, lógicamente que alguien quiera mover el cursor x posiciones a derecha o izquierda (arriba y abajo suelen comportarse traducido a derecha e izquierda), no debiera ser filtrado. Es cómodo dejar el la tecla del cursor pulsada cuando hay que avanzar bastantes caracteres, en ves de pulsar una vez por cada movimiento...
Entonces, filtrar una funcionalidad y no la otra... exige crear un array de teclas, poniendo a 1 (por ejemplo) las teclas imprimibles y a 0 las que no para filtrar solo las imprimibles... el resultado es que no funciona.

Luego he recordado que está también el evento keypress, que también sucede antes del evento change (pero detrás del keydown) y que el parametro que envía no es 'keycode', si no KeyAscii', aquí si funciona, pues todo lo que hay que hacer es anular la tecla pulsada cuando se dé la condición indicada.
Se ve que el evento change es disparado justo a la devolució de este teniendo el cuenta el valor actual de 'KeyAscii' y no el del 'Keycode'.

Sin más te pongo el código.
De ejemplo se supone un formulario con al menos un textbox (llamado al caso text1) y ya:
Código (vb) [Seleccionar]

Private KeyIsDown As Boolean


Private Sub Text1_KeyPress(KeyAscii As Integer)
   If (KeyIsDown = False) Then
       KeyIsDown = True
   Else
       KeyAscii = 0
   End If
   
   Debug.Print KeyAscii    ' con CTRL +G abre la ventana de debug, para ver los resultados filtrados...
End Sub

Private Sub Text1_KeyUp(KeyCode As Integer, Shift As Integer)
   KeyIsDown = False  ' sea o no true.
   
End Sub

Ahora cuando se pulsa una tecla, solo se acepta como una sola pulsación, sin importar el tiempo que se deje pulsada la tecla, es decir elimina la repetición.

Si deseas que otras teclas (como la de cursor) tampoco se repitan, implementa el array comentado... pero ahora en el evento Keydown.
Nota la diferencia entre una tecla de cursor a izquierda keycode=36, es ditintito de Keypress= 36 que corresponde con el carácter imprimible '$'
...se modifica como aquí consta:
Código (vb) [Seleccionar]


Private KeyIsDown As Boolean
Private CodeIsDown As Boolean   ' ojo, esta opera con keydown, la otra con KeyPress...
private charsImprimibles(0 to 255)  as byte

Private Sub Form_Load()
   dim k as integer

   charsImprimibles(13) = 1
   for k= 32 to 255
        charsImprimibles(k) = 1
   next

   ' FALTA: poner a 0 las 'keycode' que quieras que si se repitan (pulsa F2 y busca KeyCodeConstants).
    charsImprimibles(vbKeyUp)= 0
    charsImprimibles(vbKeyDown)= 0
    charsImprimibles(vbKeyLeft)= 1      ' prueba, verás que cursor a derecha exige una pulsación por cada desplazamiento.
    charsImprimibles(vbKeyRight)= 0
    ' etc...
End Sub


Private Sub Text1_KeyDown(KeyCode As Integer)
   If (charsImprimibles(KeyCode ) > 0) Then
       If (CodeIsDown = False) Then
           CodeIsDown = True
       Else
           KeyCode = 0
       End If
   End If
   
   Debug.Print KeyCode
End Sub

Private Sub Text1_KeyUp(KeyCode As Integer, Shift As Integer)
    KeyIsDown = False  ' sea o no true.
    CodeIsDown = False

End Sub



p.d: Nota que si el textbox no es multiline, el salto de línea se ignora, pero no si el textbox es multiline.
#105
Seguridad / Re: ¿Como se si mi pc tiene un virus?
10 Noviembre 2021, 16:00 PM
No hay forma fidedigna al 100% de saber si tienes un virus.
En general una caída en el rendimiento dle equipo puede elevarse en tales sospechas, pero no es la única cuasa de la caída del rendimiento de un equipo.
Incluso 'viendo' un virus operar podría resultar solamente en un programa de broma, ya que la idea de un virus es (o debe ser) pasar desapercibido, razón por la cual ni siquiera debieran elevar el consumo de los recursos del sistema d eforma significativa que llame la atención... esto era más propio en los 90.

Primero asegúrate que tu disco duro no está dañado, luego que no está lleno (o casi). Cuando apenas queda espacio el sistema se ralentiza, porque encontrar hueco libre para escribir ficheros demora excesivo tiempo, lo que se percibe como una caída del rendimiento global.
Pasa lo mismo cuando la memoria tiene también una alta ocupación. Sea porque hay muchos programas corriendo en segundo plano, sea porque tienes poca memoria sea porque un módulo de memoria se ha dañado y al ignorarlo está sucediendo las dos cosas previas.

Aún así, bastan las sospechas... para como mínimo actualizar el antivirus, desconectar la red y pasarlo a todo el equipo a todos los ficheros (hay que mirar las opciones porque suele haber desactivadas ciertas opciones que consumen mucho tiempo, pero que justamente en estos casos es cuando deben activarse).

También resulta conveniente hacer un chequeo del disco profundo, para revisar el espacio libre... esto también es necesario cuando el disco 'aparenta' estar dañado... si hay un sector dañado, conviene que el sistema rescate el contenido que exista ahí (en lo posible) y lo reubique en otra parte, luego marque el sector como dañado y no lo utilice más.
Algunos virus se 'ocultan' en el espacio libre y luego lo marcan como dañado para que el S.O. no lo utilice. Esta acción (chequeo de disco profundo) ignora la lista de sectores dañados y revisa al completo el disco duro para crear la lista desde cero (sin datos preconcebidos).
Si se hace un chequeo de disco, es buena idea al término 'defragmentar' el disco, esto hace (en lo posible), que el espacio libre quede contiguo y por tanto se amás fácil encontrarlo y también que las diferentes partes de un ficheor (en lo posible), queden contiguas, con lo que la aguja (caso de unidades mecánicas, en unidades SSD (electrónicas al 100%), esto no es necesario), no tiene que buscar otra posición y por tanto acelerar o frenar la rotación dle disco, etc...

Si a pesar de todo se ve que algo no termina de ir bien, como te han dicho vuelve a un punto de restauración anterior... esto no es formatear, esto es eliminar (de forma automática para el usaurio) ciertos cambios acontecidos hasta la fecha actual desde la última vez que se realizó un punto de restauración (el sistema puede hacerlo automáticamente si el servicio no está desactivado cuando se hagan actualizaciones importantes)... busca en tu pc 'volver a un punto de restauración anterior', si no sabes encontrarlo, busca en google añadiendo además el nombre de tu sistema operativo, para ir certero a la ubicación donde se localiza según lo que tienes... habrá miles o millones de entradas en google al respecto (sí, incluso en español).

Y si todo eso falla y se descartó daños del hardware, lo que restasería formatear, pero esta debería ser la última opción cuando quede claro que en efecto lo que hay es un virus (o varios) y que no consigues eliminarlos.... En ese caso el ofrmateo debe ser a bajo nivel (al igual que el chequeo del disco, aquí se revisan en este caso también por sectores dañados para marcarlos como no utilizables).

Cada cosa por parte... puede localizarlo en google de forma detallada, no eres ni el primeor ni el útimo que preguntará por tales temas, luego es asumible que existan muchas entradas tratando casi cualquier tema en detalle y con imagenes, paso a paso en muchas ocasiones... y para los más torpes de entender el PC, seguramente encuentren lo mismo en youtube... aunque en vez de leer algo en 5 minutos, te ocupe 45 en un vídeo alargado...
#106
Tu pregunta es demasiado elemental (y la redacción contradictoria).
Simplemente cambia el operador de comparación de un 'mayor que' a un 'menor que' o quizás a un 'menor o igual que' (según sea el caso práctico).

Es tan elemental, que no queda más remedio que derivarte a la lectura. Cabe preguntarse si entiendes el código que has puesto...
#107
Un ataque de ransomware ha afectado a los servidores de MediaMarkt en varios países del centro y el norte de Europa, según han informado fuentes de la multinacional alemana de productos electrónicos.
El ataque se ha producido a primera hora de esta mañana (día 8) y tiene consecuencias en tiendas de Holanda, Bélgica y Alemania, aunque aún no hay información oficial sobre el alcance de la intrusión.
...
El ataque llega en un momento delicado para la compañía alemana, apenas a dos semanas del inicio de la campaña del Black Friday y a un mes vista de la de Navidad. Es el período del año en el que se concentra la mayor parte de las ventas anuales de productos electrónicos.

El resto de la noticia puede leerse en:
https://www.lavanguardia.com/tecnologia/20211108/7847465/ciberataque-mediamarkt.html
#108
Para qué comprarse un tf. de 250 euros cuando no sobra el dinero... no es acaso mejor comprar uno por 150 euros y te ahorras 100, que con eso ya tienes 2/3 para el próximo ?. Pongamos que dentro de dos meses se te cae y se rompe y no fuera reparable (y la garantía no cubre accidentes de tu parte, solo defectos de fábrica)... volverías a gastarte otros 250 euros?.

Con 150 euros estás en una gama media que en realidad satisface todas las necesidades elementales. No creo que tu tengas más necesidades (de prestaciones) que el resto... A partir de cierta cantidad las prestaciones por encima que pagas, salen enormemente más caras, tanto que no merece la pena pagar el precio (salvo que el dinero te caiga por las orejas, de tanto que tienes, que no creo que sea el caso).

Sé responsable con tu dinero, compra lo que necesites, pero sin derrocharlo. Uno por 150 euros cubre las necesidades del 99% de la población, el resto es por capricho o verdadera necesidad.
#109
Software / Re: Bios
7 Noviembre 2021, 22:27 PM
Lo primero: La BIOS, no es para manazas... si no se sabe lo que se está ahciendo, lo mejor es no hacer nada, no tocarlo.

Puede que solo lo hayas desconfigurado (probablemente), pero también puedes dañar el hardware (por ejemplo estableciendo valores de voltaje o frecuencia por encima de lo que el propio hardware soporta, en esos casos a falta de conocimiento a lo sumo se elige 'automatico').

Y segundo, pon fotos que puedes hacer con el móvil y detalla dode y qué has cambiado. Para qué va uno a perder tiempo buscando y descargando el manual de la placa base de ese portátil, si al final precisas detallar lo que hayas hecho igualmente?.

Sin esas aclaraciones (imágenes y explicaciones), no tiene sentido indicarte nada más que... vayas a la última pestaña del BIOS y pulses la opción que pone "restablecer a valores de fábrica", y aceptar y rezar porque solo fuera una desconfiguración por tu parte.
#110
No existe un modo desde vb6, para evitarlo directamente.
Y no esoty seguro que puedas evitarlo con código (por ejemplo añadiendo varias variables buleanas en el keydown activarla a true si era false y evitar el cambio en el evento change, luego ponerlo en false en el evento Up, etc... creo que es complcado si no imposible sin el uso de un timer (por ejemplo).

Recuerda que la sucesión de eventos es: (Down change)+ up
Es decir si hay repetición Down y change se alternan y cuando se suelte ocurre un Up.
El problema de todo esto es que el evento Change no contiene parámetros que puedan controlarse para esto.

Es más sencillo, que filtres el contenido en el evento validate.
Si no te vale, la mejor opción es escribir tu propio control 'textbox'. En él tu pudes crear un evento 'change' que reciba como parámetro la tecla recibida y otro que señale si ya ha existido un evento down, antes de otro Up... con lo que al usar dicho control, sería extremadamente sencillo evitarlo.

En cualquier caso, es responsabilidad del usuario establecer el 'Repeat Delay' y en 'Repeat Rate' en las propiedades del teclado. No es tu problema que el usuario se quede 'pegado' a la tecla. Si es un usuario con capacidades mermadas, seguramente usará (o debiera usar) 'opciones de accesibilidad' adicionales que satisfagan sus necesidades y qu él habrá elegido o elegirá según sus necesidades.

...todavía a través de la API devicecaps, podrías leer y modificar dichos valores, pero siempre está el volver a restablecerlo a  sus valores previos... y no es buena idea, si el programa se cuelga, no podrás establecer los valores previos, si otra aplicación  (imagina otras 20) haciendo lo mismo, si no se 'resetean' en el mismo orden en que fueron tomados, se restablecerá un valor errado. En general las opciones dle usuairo, no hay que tocarlas, es el cosa dle usuario y no hay nada más irritante que una aplicación toque los valores que has establecido (entiendase resolución, tamaño de fuente, orientación de la pantalla (esta todavía vale si está a pantalla completa, porque se restablece al salir y mientras no hay otras aplicaciones que afecten), y los valores del ratón, teclado, cursor, idioma, etc...

Si insistes en necesitar dicha funcionalidad, recuerda lo que te he mencionado más arriba, podrás lograrlo a base de escribir tu propio control textbox, donde tu controles todo. Ahora, ¿merece el esfuerzo a dedicar escribir un control de usuario solo para poder disponer de esa funcionalidad?. Es mucho trabajo solo para eso (te obliga a implementar mucha funcionalidad ya existente en el textbox, que no incorpora el usercontrol), ...pero si lo haces incorpora otras funcionalidades útiles, todo junto al menos justifican abordarlo...